xref: /titanic_51/usr/src/lib/libshell/common/sh/xec.c (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
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 			{
1410 				if(shp->subshare)
1411 					sh_subtmpfile(0);
1412 				else
1413 					sh_subfork();
1414 			}
1415 			shp->inpipe = pvo;
1416 			shp->outpipe = pvn;
1417 			pvo[1] = -1;
1418 			if(sh_isoption(SH_PIPEFAIL))
1419 				job.waitall = 1;
1420 			else
1421 				job.waitall |= !pipejob && sh_isstate(SH_MONITOR);
1422 			do
1423 			{
1424 #if SHOPT_FASTPIPE
1425 				type = pipe_exec(shp,pvn,t->lst.lstlef, errorflg);
1426 #else
1427 				/* create the pipe */
1428 				sh_pipe(pvn);
1429 				/* execute out part of pipe no wait */
1430 				(t->lst.lstlef)->tre.tretyp |= showme;
1431 				type = sh_exec(t->lst.lstlef, errorflg);
1432 #endif /* SHOPT_FASTPIPE */
1433 				pipejob=1;
1434 				/* save the pipe stream-ids */
1435 				pvo[0] = pvn[0];
1436 				/* close out-part of pipe */
1437 				sh_close(pvn[1]);
1438 				/* pipeline all in one process group */
1439 				t = t->lst.lstrit;
1440 			}
1441 			/* repeat until end of pipeline */
1442 			while(!type && t->tre.tretyp==TFIL);
1443 			shp->inpipe = pvn;
1444 			shp->outpipe = 0;
1445 			if(type == 0)
1446 			{
1447 				/*
1448 				 * execute last element of pipeline
1449 				 * in the current process
1450 				 */
1451 				((Shnode_t*)t)->tre.tretyp |= showme;
1452 				sh_exec(t,flags);
1453 			}
1454 			else
1455 				/* execution failure, close pipe */
1456 				sh_pclose(pvn);
1457 			pipejob = savepipe;
1458 #ifdef SIGTSTP
1459 			if(!pipejob && sh_isstate(SH_MONITOR))
1460 				tcsetpgrp(JOBTTY,shp->pid);
1461 #endif /*SIGTSTP */
1462 			job.curpgid = savepgid;
1463 			break;
1464 		    }
1465 
1466 		    case TLST:
1467 		    {
1468 			/*  a list of commands are executed here */
1469 			do
1470 			{
1471 				sh_exec(t->lst.lstlef,errorflg|OPTIMIZE);
1472 				t = t->lst.lstrit;
1473 			}
1474 			while(t->tre.tretyp == TLST);
1475 			sh_exec(t,flags);
1476 			break;
1477 		    }
1478 
1479 		    case TAND:
1480 			if(type&TTEST)
1481 				skipexitset++;
1482 			if(sh_exec(t->lst.lstlef,OPTIMIZE)==0)
1483 				sh_exec(t->lst.lstrit,flags);
1484 			break;
1485 
1486 		    case TORF:
1487 			if(type&TTEST)
1488 				skipexitset++;
1489 			if(sh_exec(t->lst.lstlef,OPTIMIZE)!=0)
1490 				sh_exec(t->lst.lstrit,flags);
1491 			break;
1492 
1493 		    case TFOR: /* for and select */
1494 		    {
1495 			register char **args;
1496 			register int nargs;
1497 			register Namval_t *np;
1498 			int flag = errorflg|OPTIMIZE_FLAG;
1499 			struct dolnod	*argsav=0;
1500 			struct comnod	*tp;
1501 			char *cp, *trap, *nullptr = 0;
1502 			int nameref, refresh=1;
1503 			char *av[5];
1504 #if SHOPT_OPTIMIZE
1505 			int  jmpval = ((struct checkpt*)shp->jmplist)->mode;
1506 			struct checkpt buff;
1507 			void *optlist = shp->optlist;
1508 			shp->optlist = 0;
1509 			sh_tclear(t->for_.fortre);
1510 			sh_pushcontext(&buff,jmpval);
1511 			jmpval = sigsetjmp(buff.buff,0);
1512 			if(jmpval)
1513 				goto endfor;
1514 #endif /* SHOPT_OPTIMIZE */
1515 			error_info.line = t->for_.forline-shp->st.firstline;
1516 			if(!(tp=t->for_.forlst))
1517 			{
1518 				args=shp->st.dolv+1;
1519 				nargs = shp->st.dolc;
1520 				argsav=sh_arguse(shp);
1521 			}
1522 			else
1523 			{
1524 				args=sh_argbuild(shp,&argn,tp,0);
1525 				nargs = argn;
1526 			}
1527 			np = nv_open(t->for_.fornam, shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOREF);
1528 			nameref = nv_isref(np)!=0;
1529 			shp->st.loopcnt++;
1530 			cp = *args;
1531 			while(cp && shp->st.execbrk==0)
1532 			{
1533 				if(t->tre.tretyp&COMSCAN)
1534 				{
1535 					char *val;
1536 					int save_prompt;
1537 					/* reuse register */
1538 					if(refresh)
1539 					{
1540 						sh_menu(sfstderr,nargs,args);
1541 						refresh = 0;
1542 					}
1543 					save_prompt = shp->nextprompt;
1544 					shp->nextprompt = 3;
1545 					shp->timeout = 0;
1546 					shp->exitval=sh_readline(shp,&nullptr,0,1,1000*shp->st.tmout);
1547 					shp->nextprompt = save_prompt;
1548 					if(shp->exitval||sfeof(sfstdin)||sferror(sfstdin))
1549 					{
1550 						shp->exitval = 1;
1551 						break;
1552 					}
1553 					if(!(val=nv_getval(sh_scoped(shp,REPLYNOD))))
1554 						continue;
1555 					else
1556 					{
1557 						if(*(cp=val) == 0)
1558 						{
1559 							refresh++;
1560 							goto check;
1561 						}
1562 						while(type = *cp++)
1563 							if(type < '0' && type > '9')
1564 								break;
1565 						if(type!=0)
1566 							type = nargs;
1567 						else
1568 							type = (int)strtol(val, (char**)0, 10)-1;
1569 						if(type<0 || type >= nargs)
1570 							cp = "";
1571 						else
1572 							cp = args[type];
1573 					}
1574 				}
1575 				if(nameref)
1576 					nv_offattr(np,NV_REF);
1577 				else if(nv_isattr(np, NV_ARRAY))
1578 					nv_putsub(np,NIL(char*),0L);
1579 				nv_putval(np,cp,0);
1580 				if(nameref)
1581 					nv_setref(np,(Dt_t*)0,NV_VARNAME);
1582 				if(trap=shp->st.trap[SH_DEBUGTRAP])
1583 				{
1584 					av[0] = (t->tre.tretyp&COMSCAN)?"select":"for";
1585 					av[1] = t->for_.fornam;
1586 					av[2] = "in";
1587 					av[3] = cp;
1588 					av[4] = 0;
1589 					sh_debug(shp,trap,(char*)0,(char*)0,av,0);
1590 				}
1591 				sh_exec(t->for_.fortre,flag);
1592 				flag &= ~OPTIMIZE_FLAG;
1593 				if(t->tre.tretyp&COMSCAN)
1594 				{
1595 					if((cp=nv_getval(sh_scoped(shp,REPLYNOD))) && *cp==0)
1596 						refresh++;
1597 				}
1598 				else
1599 					cp = *++args;
1600 			check:
1601 				if(shp->st.breakcnt<0)
1602 					shp->st.execbrk = (++shp->st.breakcnt !=0);
1603 			}
1604 #if SHOPT_OPTIMIZE
1605 		endfor:
1606 			sh_popcontext(&buff);
1607 			sh_tclear(t->for_.fortre);
1608 			sh_optclear(shp,optlist);
1609 			if(jmpval)
1610 				siglongjmp(*shp->jmplist,jmpval);
1611 #endif /*SHOPT_OPTIMIZE */
1612 			if(shp->st.breakcnt>0)
1613 				shp->st.execbrk = (--shp->st.breakcnt !=0);
1614 			shp->st.loopcnt--;
1615 			sh_argfree(shp,argsav,0);
1616 			nv_close(np);
1617 			break;
1618 		    }
1619 
1620 		    case TWH: /* while and until */
1621 		    {
1622 			volatile int 	r=0;
1623 			int first = OPTIMIZE_FLAG;
1624 			Shnode_t *tt = t->wh.whtre;
1625 #if SHOPT_FILESCAN
1626 			Sfio_t *iop=0;
1627 			int savein,fd;
1628 #endif /*SHOPT_FILESCAN*/
1629 #if SHOPT_OPTIMIZE
1630 			int  jmpval = ((struct checkpt*)shp->jmplist)->mode;
1631 			struct checkpt buff;
1632 			void *optlist = shp->optlist;
1633 			shp->optlist = 0;
1634 			sh_tclear(t->wh.whtre);
1635 			sh_tclear(t->wh.dotre);
1636 			sh_pushcontext(&buff,jmpval);
1637 			jmpval = sigsetjmp(buff.buff,0);
1638 			if(jmpval)
1639 				goto endwhile;
1640 #endif /* SHOPT_OPTIMIZE */
1641 #if SHOPT_FILESCAN
1642 			if(type==TWH && tt->tre.tretyp==TCOM && !tt->com.comarg && tt->com.comio)
1643 			{
1644 				fd = sh_redirect(shp,tt->com.comio,3);
1645 				savein = dup(0);
1646 				if(fd==0)
1647 					fd = savein;
1648 				iop = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ);
1649 				close(0);
1650 				open("/dev/null",O_RDONLY);
1651 				shp->offsets[0] = -1;
1652 				shp->offsets[1] = 0;
1653 				if(tt->com.comset)
1654 					nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN);
1655 			}
1656 #endif /*SHOPT_FILESCAN */
1657 			shp->st.loopcnt++;
1658 			while(shp->st.execbrk==0)
1659 			{
1660 #if SHOPT_FILESCAN
1661 				if(iop)
1662 				{
1663 					if(!(shp->cur_line=sfgetr(iop,'\n',SF_STRING)))
1664 						break;
1665 				}
1666 				else
1667 #endif /*SHOPT_FILESCAN */
1668 				if((sh_exec(tt,first)==0)!=(type==TWH))
1669 					break;
1670 				r = sh_exec(t->wh.dotre,first|errorflg);
1671 				if(shp->st.breakcnt<0)
1672 					shp->st.execbrk = (++shp->st.breakcnt !=0);
1673 				/* This is for the arithmetic for */
1674 				if(shp->st.execbrk==0 && t->wh.whinc)
1675 					sh_exec((Shnode_t*)t->wh.whinc,first);
1676 				first = 0;
1677 				errorflg &= ~OPTIMIZE_FLAG;
1678 #if SHOPT_FILESCAN
1679 				shp->offsets[0] = -1;
1680 				shp->offsets[1] = 0;
1681 #endif /*SHOPT_FILESCAN */
1682 			}
1683 #if SHOPT_OPTIMIZE
1684 		endwhile:
1685 			sh_popcontext(&buff);
1686 			sh_tclear(t->wh.whtre);
1687 			sh_tclear(t->wh.dotre);
1688 			sh_optclear(shp,optlist);
1689 			if(jmpval)
1690 				siglongjmp(*shp->jmplist,jmpval);
1691 #endif /*SHOPT_OPTIMIZE */
1692 			if(shp->st.breakcnt>0)
1693 				shp->st.execbrk = (--shp->st.breakcnt !=0);
1694 			shp->st.loopcnt--;
1695 			shp->exitval= r;
1696 #if SHOPT_FILESCAN
1697 			if(iop)
1698 			{
1699 				sfclose(iop);
1700 				close(0);
1701 				dup(savein);
1702 				shp->cur_line = 0;
1703 			}
1704 #endif /*SHOPT_FILESCAN */
1705 			break;
1706 		    }
1707 		    case TARITH: /* (( expression )) */
1708 		    {
1709 			register char *trap;
1710 			char *arg[4];
1711 			error_info.line = t->ar.arline-shp->st.firstline;
1712 			arg[0] = "((";
1713 			if(!(t->ar.arexpr->argflag&ARG_RAW))
1714 				arg[1] = sh_macpat(shp,t->ar.arexpr,OPTIMIZE|ARG_ARITH);
1715 			else
1716 				arg[1] = t->ar.arexpr->argval;
1717 			arg[2] = "))";
1718 			arg[3] = 0;
1719 			if(trap=shp->st.trap[SH_DEBUGTRAP])
1720 				sh_debug(shp,trap,(char*)0, (char*)0, arg, ARG_ARITH);
1721 			if(sh_isoption(SH_XTRACE))
1722 			{
1723 				sh_trace(NIL(char**),0);
1724 				sfprintf(sfstderr,"((%s))\n",arg[1]);
1725 			}
1726 			if(t->ar.arcomp)
1727 				shp->exitval  = !arith_exec((Arith_t*)t->ar.arcomp);
1728 			else
1729 				shp->exitval = !sh_arith(arg[1]);
1730 			break;
1731 		    }
1732 
1733 		    case TIF:
1734 			if(sh_exec(t->if_.iftre,OPTIMIZE)==0)
1735 				sh_exec(t->if_.thtre,flags);
1736 			else if(t->if_.eltre)
1737 				sh_exec(t->if_.eltre, flags);
1738 			else
1739 				shp->exitval=0; /* force zero exit for if-then-fi */
1740 			break;
1741 
1742 		    case TSW:
1743 		    {
1744 			Shnode_t *tt = (Shnode_t*)t;
1745 			char *trap, *r = sh_macpat(shp,tt->sw.swarg,OPTIMIZE);
1746 			error_info.line = t->sw.swline-shp->st.firstline;
1747 			t= (Shnode_t*)(tt->sw.swlst);
1748 			if(trap=shp->st.trap[SH_DEBUGTRAP])
1749 			{
1750 				char *av[4];
1751 				av[0] = "case";
1752 				av[1] = r;
1753 				av[2] = "in";
1754 				av[3] = 0;
1755 				sh_debug(shp,trap, (char*)0, (char*)0, av, 0);
1756 			}
1757 			while(t)
1758 			{
1759 				register struct argnod	*rex=(struct argnod*)t->reg.regptr;
1760 				while(rex)
1761 				{
1762 					register char *s;
1763 					if(rex->argflag&ARG_MAC)
1764 					{
1765 						s = sh_macpat(shp,rex,OPTIMIZE|ARG_EXP);
1766 						while(*s=='\\' && s[1]==0)
1767 							s+=2;
1768 					}
1769 					else
1770 						s = rex->argval;
1771 					type = (rex->argflag&ARG_RAW);
1772 					if((type && strcmp(r,s)==0) ||
1773 						(!type && (strmatch(r,s)
1774 						|| trim_eq(r,s))))
1775 					{
1776 						do	sh_exec(t->reg.regcom,(t->reg.regflag?0:flags));
1777 						while(t->reg.regflag &&
1778 							(t=(Shnode_t*)t->reg.regnxt));
1779 						t=0;
1780 						break;
1781 					}
1782 					else
1783 						rex=rex->argnxt.ap;
1784 				}
1785 				if(t)
1786 					t=(Shnode_t*)t->reg.regnxt;
1787 			}
1788 			break;
1789 		    }
1790 
1791 		    case TTIME:
1792 		    {
1793 			/* time the command */
1794 			struct tms before,after;
1795 			const char *format = e_timeformat;
1796 			clock_t at, tm[3];
1797 #ifdef timeofday
1798 			struct timeval tb,ta;
1799 #else
1800 			clock_t bt;
1801 #endif	/* timeofday */
1802 			if(type!=TTIME)
1803 			{
1804 				sh_exec(t->par.partre,OPTIMIZE);
1805 				shp->exitval = !shp->exitval;
1806 				break;
1807 			}
1808 			if(t->par.partre)
1809 			{
1810 				long timer_on;
1811 				timer_on = sh_isstate(SH_TIMING);
1812 #ifdef timeofday
1813 				timeofday(&tb);
1814 				times(&before);
1815 #else
1816 				bt = times(&before);
1817 #endif	/* timeofday */
1818 				job.waitall = 1;
1819 				sh_onstate(SH_TIMING);
1820 				sh_exec(t->par.partre,OPTIMIZE);
1821 				if(!timer_on)
1822 					sh_offstate(SH_TIMING);
1823 				job.waitall = 0;
1824 			}
1825 			else
1826 			{
1827 #ifndef timeofday
1828 				bt = 0;
1829 #endif	/* timeofday */
1830 				before.tms_utime = before.tms_cutime = 0;
1831 				before.tms_stime = before.tms_cstime = 0;
1832 			}
1833 #ifdef timeofday
1834 			times(&after);
1835 			timeofday(&ta);
1836 			at = shp->lim.clk_tck*(ta.tv_sec-tb.tv_sec);
1837 			at +=  ((shp->lim.clk_tck*(((1000000L/2)/shp->lim.clk_tck)+(ta.tv_usec-tb.tv_usec)))/1000000L);
1838 #else
1839 			at = times(&after) - bt;
1840 #endif	/* timeofday */
1841 			tm[0] = at;
1842 			if(t->par.partre)
1843 			{
1844 				Namval_t *np = nv_open("TIMEFORMAT",shp->var_tree,NV_NOADD);
1845 				if(np)
1846 				{
1847 					format = nv_getval(np);
1848 					nv_close(np);
1849 				}
1850 				if(!format)
1851 					format = e_timeformat;
1852 			}
1853 			else
1854 				format = strchr(format+1,'\n')+1;
1855 			tm[1] = after.tms_utime - before.tms_utime;
1856 			tm[1] += after.tms_cutime - before.tms_cutime;
1857 			tm[2] = after.tms_stime - before.tms_stime;
1858 			tm[2] += after.tms_cstime - before.tms_cstime;
1859 			if(format && *format)
1860 				p_time(shp,sfstderr,sh_translate(format),tm);
1861 			break;
1862 		    }
1863 		    case TFUN:
1864 		    {
1865 			register Namval_t *np;
1866 			register struct slnod *slp;
1867 			register char *fname = ((struct functnod*)t)->functnam;
1868 			register char *cp = strrchr(fname,'.');
1869 			register Namval_t *npv=0;
1870 #if SHOPT_NAMESPACE
1871 			if(t->tre.tretyp==TNSPACE)
1872 			{
1873 				Dt_t *root,*oldroot, *top=0;
1874 				Namval_t *oldnspace = shp->namespace;
1875 				int offset = stktell(stkp);
1876 				long optindex = shp->st.optindex;
1877 				if(cp)
1878 					errormsg(SH_DICT,ERROR_exit(1),e_ident,fname);
1879 				sfputc(stkp,'.');
1880 				sfputr(stkp,fname,0);
1881 				np = nv_open(stkptr(stkp,offset),shp->var_base,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
1882 				offset = stktell(stkp);
1883 				shp->namespace = np;
1884 				if(!(root=nv_dict(np)))
1885 				{
1886 					root = dtopen(&_Nvdisc,Dtoset);
1887 					nv_putval(np,(char*)root,NV_TABLE|NV_NOFREE);
1888 					shp->st.optindex = 1;
1889 				}
1890 				if(oldnspace && dtvnext(dtvnext(shp->var_tree)))
1891 					top = dtview(shp->var_tree,0);
1892 				else if(dtvnext(shp->var_tree))
1893 					top = dtview(shp->var_tree,0);
1894 				oldroot = shp->var_tree;
1895 				dtview(root,shp->var_base);
1896 				shp->var_tree = root;
1897 				if(top)
1898 					dtview(shp->var_tree,top);
1899 				sh_exec(t->for_.fortre,flags);
1900 				if(dtvnext(shp->var_tree))
1901 					top = dtview(shp->var_tree,0);
1902 				shp->var_tree = oldroot;
1903 				if(top)
1904 					dtview(top,shp->var_tree);
1905 				shp->namespace = oldnspace;
1906 				shp->st.optindex = optindex;
1907 				break;
1908 			}
1909 #endif /* SHOPT_NAMESPACE */
1910 			/* look for discipline functions */
1911 			error_info.line = t->funct.functline-shp->st.firstline;
1912 			/* Function names cannot be special builtin */
1913 			if(cp || shp->prefix)
1914 			{
1915 				int offset = stktell(stkp);
1916 				if(shp->prefix)
1917 				{
1918 					cp = shp->prefix;
1919 					shp->prefix = 0;
1920 					npv = nv_open(cp,shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
1921 					shp->prefix = cp;
1922 					cp = fname;
1923 				}
1924 				else
1925 				{
1926 					sfwrite(stkp,fname,cp++-fname);
1927 					sfputc(stkp,0);
1928 					npv = nv_open(stkptr(stkp,offset),shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
1929 				}
1930 				offset = stktell(stkp);
1931 				sfprintf(stkp,"%s.%s%c",nv_name(npv),cp,0);
1932 				fname = stkptr(stkp,offset);
1933 			}
1934 			else if((np=nv_search(fname,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))
1935 				errormsg(SH_DICT,ERROR_exit(1),e_badfun,fname);
1936 #if SHOPT_NAMESPACE
1937 			else if(shp->namespace)
1938 			{
1939 				int offset = stktell(stkp);
1940 				sfputr(stkp,nv_name(shp->namespace),-1);
1941 				sfputc(stkp,'.');
1942 				sfputr(stkp,fname,0);
1943 				fname = stkptr(stkp,offset);
1944 			}
1945 #endif /* SHOPT_NAMESPACE */
1946 			np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE);
1947 			if(npv)
1948 			{
1949 				Namval_t *tp = npv;
1950 				if(!shp->mktype)
1951 				{
1952 					if(shp->typeinit)
1953 					{
1954 						if(tp=nv_open(shp->typeinit->nvname,shp->typedict,NV_IDENT|NV_NOFAIL))
1955 							nv_close(npv);
1956 						else
1957 							tp = npv;
1958 					}
1959 					cp = nv_setdisc(tp,cp,np,(Namfun_t*)tp);
1960 				}
1961 				nv_close(tp);
1962 				if(!cp)
1963 					errormsg(SH_DICT,ERROR_exit(1),e_baddisc,fname);
1964 			}
1965 			if(np->nvalue.rp)
1966 			{
1967 				slp = (struct slnod*)np->nvenv;
1968 				sh_funstaks(slp->slchild,-1);
1969 				stakdelete(slp->slptr);
1970 				if(shp->funload)
1971 				{
1972 					free((void*)np->nvalue.rp);
1973 					np->nvalue.rp = 0;
1974 				}
1975 
1976 			}
1977 			if(!np->nvalue.rp)
1978 			{
1979 				np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0);
1980 				memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction));
1981 			}
1982 			if(t->funct.functstak)
1983 			{
1984 				static Dtdisc_t		_Rpdisc =
1985 				{
1986 				        offsetof(struct Ufunction,fname), -1, sizeof(struct Ufunction)
1987 				};
1988 				struct functnod *fp;
1989 				slp = t->funct.functstak;
1990 				sh_funstaks(slp->slchild,1);
1991 				staklink(slp->slptr);
1992 				np->nvenv = (char*)slp;
1993 				nv_funtree(np) = (int*)(t->funct.functtre);
1994 				np->nvalue.rp->hoffset = t->funct.functloc;
1995 				np->nvalue.rp->lineno = t->funct.functline;
1996 				np->nvalue.rp->nspace = shp->namespace;
1997 				np->nvalue.rp->fname = 0;
1998 				np->nvalue.rp->fdict = shp->fun_tree;
1999 				fp = (struct functnod*)(slp+1);
2000 				if(fp->functtyp==(TFUN|FAMP))
2001 					np->nvalue.rp->fname = fp->functnam;
2002 				nv_setsize(np,fp->functline);
2003 				nv_offattr(np,NV_FPOSIX);
2004 				if(shp->funload)
2005 				{
2006 					struct Ufunction *rp = np->nvalue.rp;
2007 					rp->np = np;
2008 					if(!shp->fpathdict)
2009 						shp->fpathdict = dtopen(&_Rpdisc,Dtbag);
2010 					if(shp->fpathdict)
2011 						dtinsert(shp->fpathdict,rp);
2012 				}
2013 			}
2014 			else
2015 				nv_unset(np);
2016 			if(type&FPOSIX)
2017 				nv_onattr(np,NV_FUNCTION|NV_FPOSIX);
2018 			else
2019 				nv_onattr(np,NV_FUNCTION);
2020 			if(type&FPIN)
2021 				nv_onattr(np,NV_FTMP);
2022 			if(type&FOPTGET)
2023 				nv_onattr(np,NV_OPTGET);
2024 			break;
2025 		    }
2026 
2027 		    /* new test compound command */
2028 		    case TTST:
2029 		    {
2030 			register int n;
2031 			register char *left;
2032 			int negate = (type&TNEGATE)!=0;
2033 			if(type&TTEST)
2034 				skipexitset++;
2035 			error_info.line = t->tst.tstline-shp->st.firstline;
2036 			echeck = 1;
2037 			if((type&TPAREN)==TPAREN)
2038 			{
2039 				sh_exec(t->lst.lstlef,OPTIMIZE);
2040 				n = !shp->exitval;
2041 			}
2042 			else
2043 			{
2044 				register int traceon=0;
2045 				register char *right;
2046 				register char *trap;
2047 				char *argv[6];
2048 				n = type>>TSHIFT;
2049 				left = sh_macpat(shp,&(t->lst.lstlef->arg),OPTIMIZE);
2050 				if(type&TBINARY)
2051 					right = sh_macpat(shp,&(t->lst.lstrit->arg),((n==TEST_PEQ||n==TEST_PNE)?ARG_EXP:0)|OPTIMIZE);
2052 				if(trap=shp->st.trap[SH_DEBUGTRAP])
2053 					argv[0] = (type&TNEGATE)?((char*)e_tstbegin):"[[";
2054 				if(sh_isoption(SH_XTRACE))
2055 				{
2056 					traceon = sh_trace(NIL(char**),0);
2057 					sfwrite(sfstderr,e_tstbegin,(type&TNEGATE?5:3));
2058 				}
2059 				if(type&TUNARY)
2060 				{
2061 					if(traceon)
2062 						sfprintf(sfstderr,"-%c %s",n,sh_fmtq(left));
2063 					if(trap)
2064 					{
2065 						char unop[3];
2066 						unop[0] = '-';
2067 						unop[1] = n;
2068 						unop[2] = 0;
2069 						argv[1] = unop;
2070 						argv[2] = left;
2071 						argv[3] = "]]";
2072 						argv[4] = 0;
2073 						sh_debug(shp,trap,(char*)0,(char*)0,argv, 0);
2074 					}
2075 					n = test_unop(n,left);
2076 				}
2077 				else if(type&TBINARY)
2078 				{
2079 					char *op;
2080 					int pattern = 0;
2081 					if(trap || traceon)
2082 						op = (char*)(shtab_testops+(n&037)-1)->sh_name;
2083 					type >>= TSHIFT;
2084 					if(type==TEST_PEQ || type==TEST_PNE)
2085 						pattern=ARG_EXP;
2086 					if(trap)
2087 					{
2088 						argv[1] = left;
2089 						argv[2] = op;
2090 						argv[3] = right;
2091 						argv[4] = "]]";
2092 						argv[5] = 0;
2093 						sh_debug(shp,trap,(char*)0,(char*)0,argv, pattern);
2094 					}
2095 					n = test_binop(n,left,right);
2096 					if(traceon)
2097 					{
2098 						sfprintf(sfstderr,"%s %s ",sh_fmtq(left),op);
2099 						if(pattern)
2100 							out_pattern(sfstderr,right,-1);
2101 						else
2102 							sfputr(sfstderr,sh_fmtq(right),-1);
2103 					}
2104 				}
2105 				if(traceon)
2106 					sfwrite(sfstderr,e_tstend,4);
2107 			}
2108 			shp->exitval = ((!n)^negate);
2109 			if(!skipexitset)
2110 				exitset();
2111 			break;
2112 		    }
2113 		}
2114 		if(shp->trapnote || (shp->exitval && sh_isstate(SH_ERREXIT)) &&
2115 			t && echeck)
2116 			sh_chktrap();
2117 		/* set $_ */
2118 		if(mainloop && com0)
2119 		{
2120 			/* store last argument here if it fits */
2121 			static char	lastarg[32];
2122 			if(sh_isstate(SH_FORKED))
2123 				sh_done(shp,0);
2124 			if(shp->lastarg!= lastarg && shp->lastarg)
2125 				free(shp->lastarg);
2126 			if(strlen(comn) < sizeof(lastarg))
2127 			{
2128 				nv_onattr(L_ARGNOD,NV_NOFREE);
2129 				shp->lastarg = strcpy(lastarg,comn);
2130 			}
2131 			else
2132 			{
2133 				nv_offattr(L_ARGNOD,NV_NOFREE);
2134 				shp->lastarg = strdup(comn);
2135 			}
2136 		}
2137 		if(!skipexitset)
2138 			exitset();
2139 		if(!(OPTIMIZE))
2140 		{
2141 			if(sav != stkptr(stkp,0))
2142 				stkset(stkp,sav,0);
2143 			else if(stktell(stkp))
2144 				stkseek(stkp,0);
2145 		}
2146 		if(shp->trapnote&SH_SIGSET)
2147 			sh_exit(SH_EXITSIG|shp->lastsig);
2148 		if(was_interactive)
2149 			sh_onstate(SH_INTERACTIVE);
2150 		if(was_monitor && sh_isoption(SH_MONITOR))
2151 			sh_onstate(SH_MONITOR);
2152 		if(was_errexit)
2153 			sh_onstate(SH_ERREXIT);
2154 	}
2155 	return(shp->exitval);
2156 }
2157 
2158 int sh_run(int argn, char *argv[])
2159 {
2160 	register struct dolnod	*dp;
2161 	register struct comnod	*t = (struct comnod*)stakalloc(sizeof(struct comnod));
2162 	int			savtop = staktell();
2163 	char			*savptr = stakfreeze(0);
2164 	Opt_t			*op, *np = optctx(0, 0);
2165 	Shbltin_t		bltindata;
2166 	bltindata = sh.bltindata;
2167 	op = optctx(np, 0);
2168 	memset(t, 0, sizeof(struct comnod));
2169 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
2170 	dp->dolnum = argn;
2171 	dp->dolbot = ARG_SPARE;
2172 	memcpy(dp->dolval+ARG_SPARE, argv, (argn+1)*sizeof(char*));
2173 	t->comarg = (struct argnod*)dp;
2174 	if(!strchr(argv[0],'/'))
2175 		t->comnamp = (void*)nv_bfsearch(argv[0],sh.fun_tree,(Namval_t**)&t->comnamq,(char**)0);
2176 	argn=sh_exec((Shnode_t*)t,sh_isstate(SH_ERREXIT));
2177 	optctx(op,np);
2178 	sh.bltindata = bltindata;
2179 	if(savptr!=stakptr(0))
2180 		stakset(savptr,savtop);
2181 	else
2182 		stakseek(savtop);
2183 	return(argn);
2184 }
2185 
2186 /*
2187  * test for equality with second argument trimmed
2188  * returns 1 if r == trim(s) otherwise 0
2189  */
2190 
2191 static int trim_eq(register const char *r,register const char *s)
2192 {
2193 	register char c;
2194 	while(c = *s++)
2195 	{
2196 		if(c=='\\')
2197 			c = *s++;
2198 		if(c && c != *r++)
2199 			return(0);
2200 	}
2201 	return(*r==0);
2202 }
2203 
2204 /*
2205  * print out the command line if set -x is on
2206  */
2207 
2208 int sh_trace(register char *argv[], register int nl)
2209 {
2210 	Shell_t	*shp = &sh;
2211 	register char *cp;
2212 	register int bracket = 0;
2213 	int decl = (nl&2);
2214 	nl &= ~2;
2215 	if(sh_isoption(SH_XTRACE))
2216 	{
2217 		/* make this trace atomic */
2218 		sfset(sfstderr,SF_SHARE|SF_PUBLIC,0);
2219 		if(!(cp=nv_getval(sh_scoped(shp,PS4NOD))))
2220 			cp = "+ ";
2221 		else
2222 		{
2223 			sh_offoption(SH_XTRACE);
2224 			cp = sh_mactry(shp,cp);
2225 			sh_onoption(SH_XTRACE);
2226 		}
2227 		if(*cp)
2228 			sfputr(sfstderr,cp,-1);
2229 		if(argv)
2230 		{
2231 			char *argv0 = *argv;
2232 			nl = (nl?'\n':-1);
2233 			/* don't quote [ and [[ */
2234 			if(*(cp=argv[0])=='[' && (!cp[1] || !cp[2]&&cp[1]=='['))
2235 			{
2236 				sfputr(sfstderr,cp,*++argv?' ':nl);
2237 				bracket = 1;
2238 			}
2239 			while(cp = *argv++)
2240 			{
2241 				if(bracket==0 || *argv || *cp!=']')
2242 					cp = sh_fmtq(cp);
2243 				if(decl && shp->prefix && cp!=argv0 && *cp!='-')
2244 				{
2245 					if(*cp=='.' && cp[1]==0)
2246 						cp = shp->prefix;
2247 					else
2248 						sfputr(sfstderr,shp->prefix,'.');
2249 				}
2250 				sfputr(sfstderr,cp,*argv?' ':nl);
2251 			}
2252 			sfset(sfstderr,SF_SHARE|SF_PUBLIC,1);
2253 		}
2254 		return(1);
2255 	}
2256 	return(0);
2257 }
2258 
2259 /*
2260  * This routine creates a subshell by calling fork() or vfork()
2261  * If ((flags&COMASK)==TCOM), then vfork() is permitted
2262  * If fork fails, the shell sleeps for exponentially longer periods
2263  *   and tries again until a limit is reached.
2264  * SH_FORKLIM is the max period between forks - power of 2 usually.
2265  * Currently shell tries after 2,4,8,16, and 32 seconds and then quits
2266  * Failures cause the routine to error exit.
2267  * Parent links to here-documents are removed by the child
2268  * Traps are reset by the child
2269  * The process-id of the child is returned to the parent, 0 to the child.
2270  */
2271 
2272 static void timed_out(void *handle)
2273 {
2274 	NOT_USED(handle);
2275 	timeout = 0;
2276 }
2277 
2278 
2279 /*
2280  * called by parent and child after fork by sh_fork()
2281  */
2282 pid_t _sh_fork(register pid_t parent,int flags,int *jobid)
2283 {
2284 	static long forkcnt = 1000L;
2285 	Shell_t	*shp = &sh;
2286 	pid_t	curpgid = job.curpgid;
2287 	pid_t	postid = (flags&FAMP)?0:curpgid;
2288 	int	sig,nochild;
2289 	if(parent<0)
2290 	{
2291 		sh_sigcheck();
2292 		if((forkcnt *= 2) > 1000L*SH_FORKLIM)
2293 		{
2294 			forkcnt=1000L;
2295 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_nofork);
2296 		}
2297 		timeout = (void*)sh_timeradd(forkcnt, 0, timed_out, NIL(void*));
2298 		nochild = job_wait((pid_t)1);
2299 		if(timeout)
2300 		{
2301 			if(nochild)
2302 				pause();
2303 			else if(forkcnt>1000L)
2304 				forkcnt /= 2;
2305 			timerdel(timeout);
2306 			timeout = 0;
2307 		}
2308 		return(-1);
2309 	}
2310 	forkcnt = 1000L;
2311 	if(parent)
2312 	{
2313 		int myjob,waitall=job.waitall;
2314 		shp->nforks++;
2315 		if(job.toclear)
2316 			job_clear();
2317 		job.waitall = waitall;
2318 #ifdef JOBS
2319 		/* first process defines process group */
2320 		if(sh_isstate(SH_MONITOR))
2321 		{
2322 			/*
2323 			 * errno==EPERM means that an earlier processes
2324 			 * completed.  Make parent the job group id.
2325 			 */
2326 			if(postid==0)
2327 				job.curpgid = parent;
2328 			if(job.jobcontrol || (flags&FAMP))
2329 			{
2330 				if(setpgid(parent,job.curpgid)<0 && errno==EPERM)
2331 					setpgid(parent,parent);
2332 			}
2333 		}
2334 #endif /* JOBS */
2335 		if(!sh_isstate(SH_MONITOR) && job.waitall && postid==0)
2336 			job.curpgid = parent;
2337 		if(flags&FCOOP)
2338 			shp->cpid = parent;
2339 		myjob = job_post(parent,postid);
2340 		if(flags&FAMP)
2341 			job.curpgid = curpgid;
2342 		if(jobid)
2343 			*jobid = myjob;
2344 		return(parent);
2345 	}
2346 #if !_std_malloc
2347 	vmtrace(-1);
2348 #endif
2349 	/* This is the child process */
2350 	if(shp->trapnote&SH_SIGTERM)
2351 		sh_exit(SH_EXITSIG|SIGTERM);
2352 	shp->nforks=0;
2353 	timerdel(NIL(void*));
2354 #ifdef JOBS
2355 	if(!job.jobcontrol && !(flags&FAMP))
2356 		sh_offstate(SH_MONITOR);
2357 	if(sh_isstate(SH_MONITOR))
2358 	{
2359 		parent = getpid();
2360 		if(postid==0)
2361 			job.curpgid = parent;
2362 		while(setpgid(0,job.curpgid)<0 && job.curpgid!=parent)
2363 			job.curpgid = parent;
2364 #   ifdef SIGTSTP
2365 		if(job.curpgid==parent &&  !(flags&FAMP))
2366 			tcsetpgrp(job.fd,job.curpgid);
2367 #   endif /* SIGTSTP */
2368 	}
2369 #   ifdef SIGTSTP
2370 	if(job.jobcontrol)
2371 	{
2372 		signal(SIGTTIN,SIG_DFL);
2373 		signal(SIGTTOU,SIG_DFL);
2374 		signal(SIGTSTP,SIG_DFL);
2375 	}
2376 #   endif /* SIGTSTP */
2377 	job.jobcontrol = 0;
2378 #endif /* JOBS */
2379 	job.toclear = 1;
2380 	shp->login_sh = 0;
2381 	sh_offoption(SH_LOGIN_SHELL);
2382 	sh_onstate(SH_FORKED);
2383 	sh_onstate(SH_NOLOG);
2384 	if (shp->fn_reset)
2385 		shp->fn_depth = shp->fn_reset = 0;
2386 #if SHOPT_ACCT
2387 	sh_accsusp();
2388 #endif	/* SHOPT_ACCT */
2389 	/* Reset remaining signals to parent */
2390 	/* except for those `lost' by trap   */
2391 	sh_sigreset(2);
2392 	shp->subshell = 0;
2393 	if((flags&FAMP) && shp->coutpipe>1)
2394 		sh_close(shp->coutpipe);
2395 	sig = shp->savesig;
2396 	shp->savesig = 0;
2397 	if(sig>0)
2398 		sh_fault(sig);
2399 	sh_sigcheck();
2400 	return(0);
2401 }
2402 
2403 pid_t sh_fork(int flags, int *jobid)
2404 {
2405 	register pid_t parent;
2406 	register int sig;
2407 #if SHOPT_FASTPIPE
2408 	if(sffileno(sfstdin)<0)
2409 	{
2410 		off_t current = sfseek(sfstdin,(off_t)0,SEEK_CUR);
2411 		sfseek(sfstdin,(off_t)0,SEEK_END);
2412 		sfdisc(sfstdin,SF_POPDISC);
2413 		fcntl(sffileno(sfstdin),F_SETFD,0);
2414 		sh_iostream(0);
2415 		sfseek(sfstdin,current,SEEK_SET);
2416 	}
2417 #endif /* SHOPT_FASTPIPE */
2418 	if(!sh.pathlist)
2419 		path_get("");
2420 	sfsync(NIL(Sfio_t*));
2421 	sh.trapnote &= ~SH_SIGTERM;
2422 	job_fork(-1);
2423 	sh.savesig = -1;
2424 	while(_sh_fork(parent=fork(),flags,jobid) < 0);
2425 	sh_stats(STAT_FORKS);
2426 	sig = sh.savesig;
2427 	sh.savesig = 0;
2428 	if(sig>0)
2429 		sh_fault(sig);
2430 	job_fork(parent);
2431 	return(parent);
2432 }
2433 
2434 /*
2435  * add exports from previous scope to the new scope
2436  */
2437 static void  local_exports(register Namval_t *np, void *data)
2438 {
2439 	register Namval_t	*mp;
2440 	register char		*cp;
2441 	if(nv_isarray(np))
2442 		nv_putsub(np,NIL(char*),0);
2443 	if((cp = nv_getval(np)) && (mp = nv_search(nv_name(np), sh.var_tree, NV_ADD|HASH_NOSCOPE)) && nv_isnull(mp))
2444 		nv_putval(mp, cp, 0);
2445 }
2446 
2447 /*
2448  * This routine is used to execute the given function <fun> in a new scope
2449  * If <fun> is NULL, then arg points to a structure containing a pointer
2450  *  to a function that will be executed in the current environment.
2451  */
2452 int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg)
2453 {
2454 	register char		*trap;
2455 	register int		nsig;
2456 	register Shell_t	*shp =  &sh;
2457 	struct dolnod		*argsav=0,*saveargfor;
2458 	struct sh_scoped	savst, *prevscope = shp->st.self;
2459 	struct argnod		*envlist=0;
2460 	int			jmpval;
2461 	volatile int		r = 0;
2462 	char 			*savstak;
2463 	struct funenv		*fp;
2464 	struct checkpt		buff;
2465 	Namval_t		*nspace = shp->namespace;
2466 	if(shp->fn_depth==0)
2467 		shp->glob_options =  shp->options;
2468 	else
2469 		shp->options = shp->glob_options;
2470 #if 0
2471 	shp->st.lineno = error_info.line;
2472 #endif
2473 	*prevscope = shp->st;
2474 	sh_offoption(SH_ERREXIT);
2475 	shp->st.prevst = prevscope;
2476 	shp->st.self = &savst;
2477 	shp->topscope = (Shscope_t*)shp->st.self;
2478 	shp->st.opterror = shp->st.optchar = 0;
2479 	shp->st.optindex = 1;
2480 	shp->st.loopcnt = 0;
2481 	if(!fun)
2482 	{
2483 		fp = (struct funenv*)arg;
2484 		shp->st.real_fun = (fp->node)->nvalue.rp;
2485 		envlist = fp->env;
2486 	}
2487 	prevscope->save_tree = shp->var_tree;
2488 	sh_scope(shp,envlist,1);
2489 	if(dtvnext(prevscope->save_tree)!= (shp->namespace?shp->var_base:0))
2490 	{
2491 		/* eliminate parent scope */
2492 		nv_scan(prevscope->save_tree, local_exports,(void*)0, NV_EXPORT, NV_EXPORT|NV_NOSCOPE);
2493 	}
2494 	shp->st.save_tree = shp->var_tree;
2495 	if(!fun)
2496 	{
2497 		Namval_t *np;
2498 		if(nv_isattr(fp->node,NV_TAGGED))
2499 			sh_onoption(SH_XTRACE);
2500 		else
2501 			sh_offoption(SH_XTRACE);
2502 #if SHOPT_NAMESPACE
2503 		if((np=(fp->node)->nvalue.rp->nspace) && np!=shp->namespace)
2504 		{
2505 			Dt_t *dt = shp->var_tree;
2506 			dtview(dt,0);
2507 			dtview(dt,nv_dict(np));
2508 			shp->var_tree = nv_dict(np);
2509 			shp->namespace = np;
2510 		}
2511 #endif /* SHOPT_NAMESPACE */
2512 	}
2513 	shp->st.cmdname = argv[0];
2514 	/* save trap table */
2515 	if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
2516 	{
2517 		nsig += sizeof(char*);
2518 		memcpy(savstak=stakalloc(nsig),(char*)&shp->st.trapcom[0],nsig);
2519 	}
2520 	sh_sigreset(0);
2521 	argsav = sh_argnew(shp,argv,&saveargfor);
2522 	sh_pushcontext(&buff,SH_JMPFUN);
2523 	errorpush(&buff.err,0);
2524 	error_info.id = argv[0];
2525 	shp->st.var_local = shp->var_tree;
2526 	jmpval = sigsetjmp(buff.buff,0);
2527 	if(!fun)
2528 	{
2529 		shp->st.filename = fp->node->nvalue.rp->fname;
2530 		shp->st.funname = nv_name(fp->node);
2531 		nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
2532 		nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
2533 	}
2534 	if(jmpval == 0)
2535 	{
2536 		if(shp->fn_depth++ > MAXDEPTH)
2537 			siglongjmp(*shp->jmplist,SH_JMPERRFN);
2538 		else if(fun)
2539 			r= (*fun)(arg);
2540 		else
2541 		{
2542 			sh_exec((Shnode_t*)(nv_funtree((fp->node))),execflg|SH_ERREXIT);
2543 			r = shp->exitval;
2544 		}
2545 	}
2546 	if(--shp->fn_depth==1 && jmpval==SH_JMPERRFN)
2547 		errormsg(SH_DICT,ERROR_exit(1),e_toodeep,argv[0]);
2548 	sh_popcontext(&buff);
2549 	if (shp->st.self != &savst)
2550 		shp->var_tree = (Dt_t*)savst.save_tree;
2551 	sh_unscope(shp);
2552 	shp->namespace = nspace;
2553 	shp->var_tree = (Dt_t*)prevscope->save_tree;
2554 	if(shp->topscope != (Shscope_t*)shp->st.self)
2555 		sh_setscope(shp->topscope);
2556 	sh_argreset(shp,argsav,saveargfor);
2557 	trap = shp->st.trapcom[0];
2558 	shp->st.trapcom[0] = 0;
2559 	sh_sigreset(1);
2560 	if (shp->st.self != &savst)
2561 		*shp->st.self = shp->st;
2562 	shp->st = *prevscope;
2563 	shp->topscope = (Shscope_t*)prevscope;
2564 	nv_getval(sh_scoped(shp,IFSNOD));
2565 	if(nsig)
2566 		memcpy((char*)&shp->st.trapcom[0],savstak,nsig);
2567 	shp->trapnote=0;
2568 	if(nsig)
2569 		stakset(savstak,0);
2570 	shp->options = shp->glob_options;
2571 	if(trap)
2572 	{
2573 		sh_trap(trap,0);
2574 		free(trap);
2575 	}
2576 	if(shp->exitval > SH_EXITSIG)
2577 		sh_fault(shp->exitval&SH_EXITMASK);
2578 	if(jmpval > SH_JMPFUN)
2579 	{
2580 		sh_chktrap();
2581 		siglongjmp(*shp->jmplist,jmpval);
2582 	}
2583 	return(r);
2584 }
2585 
2586 static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct argnod *envlist,int execflg)
2587 {
2588 	struct funenv fun;
2589 	char *fname = nv_getval(SH_FUNNAMENOD);
2590 	struct Level	*lp =(struct Level*)(SH_LEVELNOD->nvfun);
2591 	int		level;
2592 	sh_stats(STAT_FUNCT);
2593 	if(!lp->hdr.disc)
2594 		lp = init_level(0);
2595 	if((struct sh_scoped*)shp->topscope != shp->st.self)
2596 		sh_setscope(shp->topscope);
2597 	level = lp->maxlevel = shp->dot_depth + shp->fn_depth+1;
2598 	SH_LEVELNOD->nvalue.s = lp->maxlevel;
2599 	shp->st.lineno = error_info.line;
2600 	if(nv_isattr(np,NV_FPOSIX))
2601 	{
2602 		char *save;
2603 		int loopcnt = shp->st.loopcnt;
2604 		shp->posix_fun = np;
2605 		save = argv[-1];
2606 		argv[-1] = 0;
2607 		shp->st.funname = nv_name(np);
2608 		nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE);
2609 		opt_info.index = opt_info.offset = 0;
2610 		error_info.errors = 0;
2611 		shp->st.loopcnt = 0;
2612 		b_dot_cmd(argn+1,argv-1,&shp->bltindata);
2613 		shp->st.loopcnt = loopcnt;
2614 		argv[-1] = save;
2615 	}
2616 	else
2617 	{
2618 		fun.env = envlist;
2619 		fun.node = np;
2620 		sh_funscope(argn,argv,0,&fun,execflg);
2621 	}
2622 	if(level-- != nv_getnum(SH_LEVELNOD))
2623 	{
2624 		Shscope_t *sp = sh_getscope(0,SEEK_END);
2625 		sh_setscope(sp);
2626 	}
2627 	lp->maxlevel = level;
2628 	SH_LEVELNOD->nvalue.s = lp->maxlevel;
2629 #if 0
2630 	nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
2631 #else
2632 	nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE);
2633 #endif
2634 	nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
2635 }
2636 
2637 /*
2638  * external interface to execute a function without arguments
2639  * <np> is the function node
2640  * If <nq> is not-null, then sh.name and sh.subscript will be set
2641  */
2642 int sh_fun(Namval_t *np, Namval_t *nq, char *argv[])
2643 {
2644 	Shell_t		*shp = &sh;
2645 	register int offset;
2646 	register char *base;
2647 	Namval_t node;
2648 	struct Namref	nr;
2649 	long		mode;
2650 	char		*prefix = shp->prefix;
2651 	int n=0;
2652 	char *av[2];
2653 	Fcin_t save;
2654 	fcsave(&save);
2655 	if((offset=staktell())>0)
2656 		base=stakfreeze(0);
2657 	shp->prefix = 0;
2658 	if(!argv)
2659 	{
2660 		argv = av;
2661 		argv[1]=0;
2662 	}
2663 	argv[0] = nv_name(np);
2664 	while(argv[n])
2665 		n++;
2666 	if(nq)
2667 		mode = set_instance(nq,&node, &nr);
2668 	if(is_abuiltin(np))
2669 	{
2670 		int jmpval;
2671 		struct checkpt buff;
2672 		Shbltin_t *bp = &sh.bltindata;
2673 		sh_pushcontext(&buff,SH_JMPCMD);
2674 		jmpval = sigsetjmp(buff.buff,1);
2675 		if(jmpval == 0)
2676 		{
2677 			bp->bnode = np;
2678 			bp->ptr = nv_context(np);
2679 			errorpush(&buff.err,0);
2680 			error_info.id = argv[0];
2681 			opt_info.index = opt_info.offset = 0;
2682 			opt_info.disc = 0;
2683 			sh.exitval = 0;
2684 			sh.exitval = (*funptr(np))(n,argv,(void*)bp);
2685 		}
2686 		sh_popcontext(&buff);
2687 		if(jmpval>SH_JMPCMD)
2688 			siglongjmp(*sh.jmplist,jmpval);
2689 	}
2690 	else
2691 		sh_funct(shp,np,n,argv,(struct argnod*)0,sh_isstate(SH_ERREXIT));
2692 	if(nq)
2693 		unset_instance(nq, &node, &nr, mode);
2694 	fcrestore(&save);
2695 	if(offset>0)
2696 		stakset(base,offset);
2697 	shp->prefix = prefix;
2698 	return(sh.exitval);
2699 }
2700 
2701 /*
2702  * This dummy routine is called by built-ins that do recursion
2703  * on the file system (chmod, chgrp, chown).  It causes
2704  * the shell to invoke the non-builtin version in this case
2705  */
2706 int cmdrecurse(int argc, char* argv[], int ac, char* av[])
2707 {
2708 	NOT_USED(argc);
2709 	NOT_USED(argv[0]);
2710 	NOT_USED(ac);
2711 	NOT_USED(av[0]);
2712 	return(SH_RUNPROG);
2713 }
2714 
2715 /*
2716  * set up pipe for cooperating process
2717  */
2718 static void coproc_init(Shell_t *shp, int pipes[])
2719 {
2720 	int outfd;
2721 	if(shp->coutpipe>=0 && shp->cpid)
2722 		errormsg(SH_DICT,ERROR_exit(1),e_pexists);
2723 	shp->cpid = 0;
2724 	if(shp->cpipe[0]<=0 || shp->cpipe[1]<=0)
2725 	{
2726 		/* first co-process */
2727 		sh_pclose(shp->cpipe);
2728 		sh_pipe(shp->cpipe);
2729 		if((outfd=shp->cpipe[1]) < 10)
2730 		{
2731 		        int fd=fcntl(shp->cpipe[1],F_DUPFD,10);
2732 			if(fd>=10)
2733 			{
2734 			        shp->fdstatus[fd] = (shp->fdstatus[outfd]&~IOCLEX);
2735 				close(outfd);
2736 			        shp->fdstatus[outfd] = IOCLOSE;
2737 				shp->cpipe[1] = fd;
2738 			}
2739 		}
2740 		if(fcntl(*shp->cpipe,F_SETFD,FD_CLOEXEC)>=0)
2741 			shp->fdstatus[shp->cpipe[0]] |= IOCLEX;
2742 		shp->fdptrs[shp->cpipe[0]] = shp->cpipe;
2743 
2744 		if(fcntl(shp->cpipe[1],F_SETFD,FD_CLOEXEC) >=0)
2745 			shp->fdstatus[shp->cpipe[1]] |= IOCLEX;
2746 	}
2747 	shp->outpipe = shp->cpipe;
2748 	sh_pipe(shp->inpipe=pipes);
2749 	shp->coutpipe = shp->inpipe[1];
2750 	shp->fdptrs[shp->coutpipe] = &shp->coutpipe;
2751 	if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
2752 		shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
2753 }
2754 
2755 #if SHOPT_SPAWN
2756 
2757 
2758 #if SHOPT_AMP || !defined(_lib_fork)
2759 /*
2760  * print out function definition
2761  */
2762 static void print_fun(register Namval_t* np, void *data)
2763 {
2764 	register char *format;
2765 	NOT_USED(data);
2766 	if(!is_afunction(np) || !np->nvalue.ip)
2767 		return;
2768 	if(nv_isattr(np,NV_FPOSIX))
2769 		format="%s()\n{ ";
2770 	else
2771 		format="function %s\n{ ";
2772 	sfprintf(sfstdout,format,nv_name(np));
2773 	sh_deparse(sfstdout,(Shnode_t*)(nv_funtree(np)),0);
2774 	sfwrite(sfstdout,"}\n",2);
2775 }
2776 
2777 /*
2778  * create a shell script consisting of t->fork.forktre and execute it
2779  */
2780 static int run_subshell(const Shnode_t *t,pid_t grp)
2781 {
2782 	static const char prolog[] = "(print $(typeset +A);set; typeset -p; print .sh.dollar=$$;set +o)";
2783 	register int i, fd, trace = sh_isoption(SH_XTRACE);
2784 	int pin,pout;
2785 	pid_t pid;
2786 	char *arglist[2], *envlist[2], devfd[12], *cp;
2787 	Sfio_t *sp = sftmp(0);
2788 	envlist[0] = "_=" SH_ID;
2789 	envlist[1] = 0;
2790 	arglist[0] = error_info.id?error_info.id:sh.shname;
2791 	if(*arglist[0]=='-')
2792 		arglist[0]++;
2793 	arglist[1] = devfd;
2794 	strncpy(devfd,e_devfdNN,sizeof(devfd));
2795 	arglist[2] = 0;
2796 	sfstack(sfstdout,sp);
2797 	if(trace)
2798 		sh_offoption(SH_XTRACE);
2799 	sfwrite(sfstdout,"typeset -A -- ",14);
2800 	sh_trap(prolog,0);
2801 	nv_scan(sh.fun_tree, print_fun, (void*)0,0, 0);
2802 	if(sh.st.dolc>0)
2803 	{
2804 		/* pass the positional parameters */
2805 		char **argv = sh.st.dolv+1;
2806 		sfwrite(sfstdout,"set --",6);
2807 		while(*argv)
2808 			sfprintf(sfstdout," %s",sh_fmtq(*argv++));
2809 		sfputc(sfstdout,'\n');
2810 	}
2811 	pin = (sh.inpipe?sh.inpipe[1]:0);
2812 	pout = (sh.outpipe?sh.outpipe[0]:0);
2813 	for(i=3; i < 10; i++)
2814 	{
2815 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
2816 		{
2817 			sfprintf(sfstdout,"exec %d<&%d\n",i,i);
2818 			fcntl(i,F_SETFD,0);
2819 		}
2820 	}
2821 	sfprintf(sfstdout,"LINENO=%d\n",t->fork.forkline);
2822 	if(trace)
2823 	{
2824 		sfwrite(sfstdout,"set -x\n",7);
2825 		sh_onoption(SH_XTRACE);
2826 	}
2827 	sfstack(sfstdout,NIL(Sfio_t*));
2828 	sh_deparse(sp,t->fork.forktre,0);
2829 	sfseek(sp,(Sfoff_t)0,SEEK_SET);
2830 	fd = sh_dup(sffileno(sp));
2831 	cp = devfd+8;
2832 	if(fd>9)
2833 		*cp++ = '0' + (fd/10);
2834 	*cp++ = '0' + fd%10;
2835 	*cp = 0;
2836 	sfclose(sp);
2837 	sfsync(NIL(Sfio_t*));
2838 	if(!sh.shpath)
2839 		sh.shpath = pathshell();
2840 	pid = spawnveg(sh.shpath,arglist,envlist,grp);
2841 	close(fd);
2842 	for(i=3; i < 10; i++)
2843 	{
2844 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
2845 			fcntl(i,F_SETFD,FD_CLOEXEC);
2846 	}
2847 	if(pid <=0)
2848 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arglist[0]);
2849 	return(pid);
2850 }
2851 #endif /* !_lib_fork */
2852 
2853 static void sigreset(int mode)
2854 {
2855 	register char   *trap;
2856 	register int sig=sh.st.trapmax;
2857 	while(sig-- > 0)
2858 	{
2859 		if((trap=sh.st.trapcom[sig]) && *trap==0)
2860 			signal(sig,mode?sh_fault:SIG_IGN);
2861 	}
2862 }
2863 
2864 /*
2865  * A combined fork/exec for systems with slow or non-existent fork()
2866  */
2867 static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,int flag)
2868 {
2869 	static pid_t	spawnpid;
2870 	static int	savetype;
2871 	static int	savejobid;
2872 	struct checkpt	buff;
2873 	int		otype=0, jmpval;
2874 	volatile int	jobwasset=0, scope=0, sigwasset=0;
2875 	char		**arge, *path;
2876 	volatile pid_t	grp = 0;
2877 	Pathcomp_t	*pp;
2878 	if(flag)
2879 	{
2880 		otype = savetype;
2881 		savetype=0;
2882 	}
2883 #   if SHOPT_AMP || !defined(_lib_fork)
2884 	if(!argv)
2885 	{
2886 		register Shnode_t *tchild = t->fork.forktre;
2887 		int optimize=0;
2888 		otype = t->tre.tretyp;
2889 		savetype = otype;
2890 		spawnpid = 0;
2891 #	ifndef _lib_fork
2892 		if((tchild->tre.tretyp&COMMSK)==TCOM)
2893 		{
2894 			Namval_t *np = (Namval_t*)(tchild->com.comnamp);
2895 			if(np)
2896 			{
2897 				path = nv_name(np);
2898 				if(!nv_isattr(np,BLT_ENV))
2899 					np=0;
2900 				else if(strcmp(path,"echo")==0 || memcmp(path,"print",5)==0)
2901 					np=0;
2902 			}
2903 			else if(!tchild->com.comarg)
2904 				optimize=1;
2905 			else if(tchild->com.comtyp&COMSCAN)
2906 			{
2907 				if(tchild->com.comarg->argflag&ARG_RAW)
2908 					path = tchild->com.comarg->argval;
2909 				else
2910 					path = 0;
2911 			}
2912 			else
2913 				path = ((struct dolnod*)tchild->com.comarg)->dolval[ARG_SPARE];
2914 			if(!np && path && !nv_search(path,shp->fun_tree,0))
2915 				optimize=1;
2916 		}
2917 #	endif
2918 		sh_pushcontext(&buff,SH_JMPIO);
2919 		jmpval = sigsetjmp(buff.buff,0);
2920 		{
2921 			if((otype&FINT) && !sh_isstate(SH_MONITOR))
2922 			{
2923 				signal(SIGQUIT,SIG_IGN);
2924 				signal(SIGINT,SIG_IGN);
2925 				if(!shp->st.ioset)
2926 				{
2927 					sh_iosave(shp,0,buff.topfd,(char*)0);
2928 					sh_iorenumber(shp,sh_chkopen(e_devnull),0);
2929 				}
2930 			}
2931 			if(otype&FPIN)
2932 			{
2933 				int fd = shp->inpipe[1];
2934 				sh_iosave(shp,0,buff.topfd,(char*)0);
2935 				sh_iorenumber(shp,shp->inpipe[0],0);
2936 				if(fd>=0 && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(fd,F_SETFD,FD_CLOEXEC)>=0)
2937 					shp->fdstatus[fd] |= IOCLEX;
2938 			}
2939 			if(otype&FPOU)
2940 			{
2941 				sh_iosave(shp,1,buff.topfd,(char*)0);
2942 				sh_iorenumber(shp,sh_dup(shp->outpipe[1]),1);
2943 				if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
2944 					shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
2945 			}
2946 
2947 			if(t->fork.forkio)
2948 				sh_redirect(shp,t->fork.forkio,0);
2949 			if(optimize==0)
2950 			{
2951 #ifdef SIGTSTP
2952 				if(job.jobcontrol)
2953 				{
2954 					signal(SIGTTIN,SIG_DFL);
2955 					signal(SIGTTOU,SIG_DFL);
2956 				}
2957 #endif /* SIGTSTP */
2958 #ifdef JOBS
2959 				if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
2960 				{
2961 					if((otype&FAMP) || job.curpgid==0)
2962 						grp = 1;
2963 					else
2964 						grp = job.curpgid;
2965 				}
2966 #endif /* JOBS */
2967 				spawnpid = run_subshell(t,grp);
2968 			}
2969 			else
2970 			{
2971 				sh_exec(tchild,SH_NTFORK);
2972 				if(jobid)
2973 					*jobid = savejobid;
2974 			}
2975 		}
2976 		sh_popcontext(&buff);
2977 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
2978 		{
2979 			signal(SIGQUIT,sh_fault);
2980 			signal(SIGINT,sh_fault);
2981 		}
2982 		if((otype&FPIN) && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(shp->inpipe[1],F_SETFD,FD_CLOEXEC)>=0)
2983 			shp->fdstatus[shp->inpipe[1]] &= ~IOCLEX;
2984 		if(t->fork.forkio || otype)
2985 			sh_iorestore(shp,buff.topfd,jmpval);
2986 		if(optimize==0)
2987 		{
2988 #ifdef SIGTSTP
2989 			if(job.jobcontrol)
2990 			{
2991 				signal(SIGTTIN,SIG_IGN);
2992 				signal(SIGTTOU,SIG_IGN);
2993 			}
2994 #endif /* SIGTSTP */
2995 			if(spawnpid>0)
2996 				_sh_fork(spawnpid,otype,jobid);
2997 			if(grp>0 && !(otype&FAMP))
2998 			{
2999 				while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
3000 					job.curpgid = spawnpid;
3001 			}
3002 		}
3003 		savetype=0;
3004 		if(jmpval>SH_JMPIO)
3005 			siglongjmp(*shp->jmplist,jmpval);
3006 		if(spawnpid<0 && (otype&FCOOP))
3007 		{
3008 			sh_close(shp->coutpipe);
3009 			sh_close(shp->cpipe[1]);
3010 			shp->cpipe[1] = -1;
3011 			shp->coutpipe = -1;
3012 		}
3013 		shp->exitval = 0;
3014 		return(spawnpid);
3015 	}
3016 #   endif /* !_lib_fork */
3017 	sh_pushcontext(&buff,SH_JMPCMD);
3018 	errorpush(&buff.err,ERROR_SILENT);
3019 	jmpval = sigsetjmp(buff.buff,0);
3020 	if(jmpval == 0)
3021 	{
3022 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
3023 		{
3024 			signal(SIGQUIT,SIG_IGN);
3025 			signal(SIGINT,SIG_IGN);
3026 		}
3027 		spawnpid = -1;
3028 		if(t->com.comio)
3029 			sh_redirect(shp,t->com.comio,0);
3030 		error_info.id = *argv;
3031 		if(t->com.comset)
3032 		{
3033 			scope++;
3034 			sh_scope(shp,t->com.comset,0);
3035 		}
3036 		if(!strchr(path=argv[0],'/'))
3037 		{
3038 			Namval_t *np;
3039 			if((np=nv_search(path,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
3040 				path = nv_getval(np);
3041 			else if(path_absolute(path,NIL(Pathcomp_t*)))
3042 			{
3043 			path = stkptr(shp->stk,PATH_OFFSET);
3044 			stkfreeze(shp->stk,0);
3045 		}
3046 		else
3047 		{
3048 			pp=path_get(path);
3049 			while(pp)
3050 			{
3051 				if(pp->len==1 && *pp->name=='.')
3052 					break;
3053 				pp = pp->next;
3054 			}
3055 			if(!pp)
3056 				path = 0;
3057 		}
3058 	}
3059 	else if(sh_isoption(SH_RESTRICTED))
3060 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,path);
3061 	if(!path)
3062 	{
3063 		spawnpid = -1;
3064 		goto fail;
3065 	}
3066 	arge = sh_envgen();
3067 	shp->exitval = 0;
3068 #ifdef SIGTSTP
3069 		if(job.jobcontrol)
3070 		{
3071 			signal(SIGTTIN,SIG_DFL);
3072 			signal(SIGTTOU,SIG_DFL);
3073 			jobwasset++;
3074 		}
3075 #endif /* SIGTSTP */
3076 #ifdef JOBS
3077 		if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
3078 		{
3079 			if((otype&FAMP) || job.curpgid==0)
3080 				grp = 1;
3081 			else
3082 				grp = job.curpgid;
3083 		}
3084 #endif /* JOBS */
3085 
3086 		sfsync(NIL(Sfio_t*));
3087 		sigreset(0);	/* set signals to ignore */
3088 		sigwasset++;
3089 	        /* find first path that has a library component */
3090 		for(pp=path_get(argv[0]); pp && !pp->lib ; pp=pp->next);
3091 		spawnpid = path_spawn(path,argv,arge,pp,(grp<<1)|1);
3092 		if(spawnpid < 0 && errno==ENOEXEC)
3093 		{
3094 			char *devfd;
3095 			int fd = open(path,O_RDONLY);
3096 			argv[-1] = argv[0];
3097 			argv[0] = path;
3098 			if(fd>=0)
3099 			{
3100 				struct stat statb;
3101 				sfprintf(sh.strbuf,"/dev/fd/%d",fd);
3102 				if(stat(devfd=sfstruse(sh.strbuf),&statb)>=0)
3103 					argv[0] =  devfd;
3104 			}
3105 			if(!shp->shpath)
3106 				shp->shpath = pathshell();
3107 			spawnpid = path_spawn(shp->shpath,&argv[-1],arge,pp,(grp<<1)|1);
3108 			if(fd>=0)
3109 				close(fd);
3110 			argv[0] = argv[-1];
3111 		}
3112 	fail:
3113 		if(spawnpid < 0) switch(errno=shp->path_err)
3114 		{
3115 		    case ENOENT:
3116 			errormsg(SH_DICT,ERROR_system(ERROR_NOENT),e_found+4);
3117 		    default:
3118 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4);
3119 		}
3120 	}
3121 	else
3122 		exitset();
3123 	sh_popcontext(&buff);
3124 	if(buff.olist)
3125 		free_list(buff.olist);
3126 #ifdef SIGTSTP
3127 	if(jobwasset)
3128 	{
3129 		signal(SIGTTIN,SIG_IGN);
3130 		signal(SIGTTOU,SIG_IGN);
3131 	}
3132 #endif /* SIGTSTP */
3133 	if(sigwasset)
3134 		sigreset(1);	/* restore ignored signals */
3135 	if(scope)
3136 	{
3137 		sh_unscope(shp);
3138 		if(jmpval==SH_JMPSCRIPT)
3139 			nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN);
3140 	}
3141 	if(t->com.comio)
3142 		sh_iorestore(shp,buff.topfd,jmpval);
3143 	if(jmpval>SH_JMPCMD)
3144 		siglongjmp(*shp->jmplist,jmpval);
3145 	if(spawnpid>0)
3146 	{
3147 		_sh_fork(spawnpid,otype,jobid);
3148 #ifdef JOBS
3149 		if(grp==1)
3150 			job.curpgid = spawnpid;
3151 #   ifdef SIGTSTP
3152 		if(grp>0 && !(otype&FAMP))
3153 		{
3154 			while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
3155 				job.curpgid = spawnpid;
3156 		}
3157 #   endif /* SIGTSTP */
3158 #endif /* JOBS */
3159 		savejobid = *jobid;
3160 		if(otype)
3161 			return(0);
3162 	}
3163 	return(spawnpid);
3164 }
3165 
3166 #   ifdef _was_lib_fork
3167 #	define _lib_fork	1
3168 #   endif
3169 #   ifndef _lib_fork
3170 	pid_t fork(void)
3171 	{
3172 		errormsg(SH_DICT,ERROR_exit(3),e_notimp,"fork");
3173 		return(-1);
3174 	}
3175 #   endif /* _lib_fork */
3176 #endif /* SHOPT_SPAWN */
3177