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