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