1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * UNIX shell parse tree executer
31 #include "variables.h"
39 #include "FEATURE/time"
40 #include "FEATURE/externs"
41 #include "FEATURE/locale"
49 # include <ast_vfork.h>
51 # define vfork() fork()
54 #define SH_NTFORK SH_TIMING
58 #endif /* _lib_nice */
60 # define spawnveg(a,b,c,d) spawnve(a,b,c)
61 #endif /* !_lib_spawnveg */
63 static pid_t
sh_ntfork(Shell_t
*,const Shnode_t
*,char*[],int*,int);
64 #endif /* SHOPT_SPAWN */
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
[]);
79 /* ======== command execution ========*/
82 * print time <t> in h:m:s format with precision <p>
84 static void l_time(Sfio_t
*outfile
,register clock_t t
,int p
)
86 register int min
, sec
, frac
;
90 frac
= t
%sh
.lim
.clk_tck
;
91 frac
= (frac
*100)/sh
.lim
.clk_tck
;
98 sfprintf(outfile
,"%dh",hr
);
100 sfprintf(outfile
,"%dm%d%c%0*ds",min
,sec
,GETDECIMAL(0),p
,frac
);
102 sfprintf(outfile
,"%dm%ds",min
,sec
);
105 static int p_time(Shell_t
*shp
, Sfio_t
*out
, const char *format
, clock_t *tm
)
107 int c
,p
,l
,n
,offset
= staktell();
110 Stk_t
*stkp
= shp
->stk
;
111 for(first
=format
; c
= *format
; format
++)
115 sfwrite(stkp
, first
, format
-first
);
118 if((c
= *++format
) == '%')
123 if(c
>='0' && c
<='9')
125 p
= (c
>'3')?3:(c
-'0');
131 d
= 100.*(((double)(tm
[1]+tm
[2]))/d
);
146 stkseek(stkp
,offset
);
147 errormsg(SH_DICT
,ERROR_exit(0),e_badtformat
,c
);
150 d
= (double)tm
[n
]/sh
.lim
.clk_tck
;
153 l_time(stkp
, tm
[n
], p
);
155 sfprintf(stkp
,"%.*f",p
, d
);
159 sfwrite(stkp
,first
, format
-first
);
161 n
= stktell(stkp
)-offset
;
162 sfwrite(out
,stkptr(stkp
,offset
),n
);
163 stkseek(stkp
,offset
);
169 * clear argument pointers that point into the stack
171 static int p_arg(struct argnod
*,int);
172 static int p_switch(struct regnod
*);
173 static int p_comarg(register struct comnod
*com
)
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
)
181 /* call builtin to cleanup state */
182 Shbltin_t
*bp
= &sh
.bltindata
;
183 void *save_ptr
= bp
->ptr
;
184 void *save_data
= bp
->data
;
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
);
192 bp
->data
= save_data
;
195 if(com
->comarg
&& !np
)
200 extern void sh_optclear(Shell_t
*, void*);
202 static int sh_tclear(register Shnode_t
*t
)
207 switch(t
->tre
.tretyp
&COMMSK
)
211 return(sh_tclear(t
->par
.partre
));
213 return(p_comarg((struct comnod
*)t
));
216 return(sh_tclear(t
->fork
.forktre
));
218 n
=sh_tclear(t
->if_
.iftre
);
219 n
+=sh_tclear(t
->if_
.thtre
);
220 n
+=sh_tclear(t
->if_
.eltre
);
224 n
=sh_tclear((Shnode_t
*)(t
->wh
.whinc
));
225 n
+=sh_tclear(t
->wh
.whtre
);
226 n
+=sh_tclear(t
->wh
.dotre
);
232 n
=sh_tclear(t
->lst
.lstlef
);
233 return(n
+sh_tclear(t
->lst
.lstrit
));
235 return(p_arg(t
->ar
.arexpr
,ARG_ARITH
));
237 n
=sh_tclear(t
->for_
.fortre
);
238 return(n
+sh_tclear((Shnode_t
*)t
->for_
.forlst
));
240 n
=p_arg(t
->sw
.swarg
,0);
241 return(n
+p_switch(t
->sw
.swlst
));
243 n
=sh_tclear(t
->funct
.functtre
);
244 return(n
+sh_tclear((Shnode_t
*)t
->funct
.functargs
));
246 if((t
->tre
.tretyp
&TPAREN
)==TPAREN
)
247 return(sh_tclear(t
->lst
.lstlef
));
250 n
=p_arg(&(t
->lst
.lstlef
->arg
),0);
251 if(t
->tre
.tretyp
&TBINARY
)
252 n
+=p_arg(&(t
->lst
.lstrit
->arg
),0);
258 static int p_arg(register struct argnod
*arg
,int flag
)
262 if(strlen(arg
->argval
) || (arg
->argflag
==ARG_RAW
))
265 sh_tclear((Shnode_t
*)arg
->argchn
.ap
);
267 sh_tclear(((struct fornod
*)arg
->argchn
.ap
)->fortre
);
268 arg
= arg
->argnxt
.ap
;
273 static int p_switch(register struct regnod
*reg
)
278 n
+=p_arg(reg
->regptr
,0);
279 n
+=sh_tclear(reg
->regcom
);
284 # define OPTIMIZE_FLAG (ARG_OPTIMIZE)
285 # define OPTIMIZE (flags&OPTIMIZE_FLAG)
287 # define OPTIMIZE_FLAG (0)
288 # define OPTIMIZE (0)
289 # define sh_tclear(x)
290 #endif /* SHOPT_OPTIMIZE */
292 static void out_pattern(Sfio_t
*iop
, register const char *cp
, int n
)
305 sfputr(iop
,"$'\\n",'\'');
312 case '<': case '>': case ';':
313 case '$': case '`': case '\t':
322 static void out_string(Sfio_t
*iop
, register const char *cp
, int c
, int quoted
)
326 int n
= stktell(stkstd
);
328 if(iop
==stkstd
&& cp
==stkptr(stkstd
,n
))
330 *stkptr(stkstd
,stktell(stkstd
)-1) = c
;
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
348 static void put_level(Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
351 struct Level
*lp
= (struct Level
*)fp
;
352 int16_t level
, oldlevel
= (int16_t)nv_getnum(np
);
353 nv_putv(np
,val
,flags
,fp
);
356 fp
= nv_stack(np
, NIL(Namfun_t
*));
357 if(fp
&& !fp
->nofree
)
361 level
= nv_getnum(np
);
362 if(level
<0 || level
> lp
->maxlevel
)
364 nv_putv(np
, (char*)&oldlevel
, NV_INT16
, fp
);
365 /* perhaps this should be an error */
370 if(sp
= sh_getscope(level
,SEEK_SET
))
373 error_info
.id
= sp
->cmdname
;
378 static const Namdisc_t level_disc
= { sizeof(struct Level
), put_level
};
380 static struct Level
*init_level(int level
)
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
);
393 * write the current common on the stack and make it available as .sh.command
395 int sh_debug(Shell_t
*shp
, const char *trap
, const char *name
, const char *subscript
, char *const argv
[], int flags
)
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
;
414 out_string(iop
,subscript
,']',1);
416 if(!(flags
&ARG_APPEND
))
418 if(!(flags
&ARG_ASSIGN
))
422 if(*argv
&& !(flags
&ARG_RAW
))
423 out_string(iop
, *argv
++,' ', 0);
424 n
= (flags
&ARG_ARITH
);
427 if((flags
&ARG_EXP
) && argv
[1]==0)
428 out_pattern(iop
, cp
,' ');
430 out_string(iop
, cp
,' ',n
?0: (flags
&(ARG_RAW
|ARG_NOGLOB
))||*argv
);
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
))
443 nv_putval(SH_LEVELNOD
,(char*)&level
,NV_INT16
);
445 shp
->st
.trap
[SH_DEBUGTRAP
] = 0;
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
);
454 if(sav
!= stkptr(stkp
,0))
457 stkseek(stkp
,offset
);
462 * Given stream <iop> compile and execute
464 int sh_eval(register Sfio_t
*iop
, int mode
)
466 register Shnode_t
*t
;
467 Shell_t
*shp
= sh_getinterp();
468 struct slnod
*saveslp
= shp
->st
.staklist
;
470 struct checkpt
*pp
= (struct checkpt
*)shp
->jmplist
;
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 */
477 #define SH_TOPFUN 0x8000 /* this is a temporary tksh hack */
478 if (mode
& SH_TOPFUN
)
483 sh_pushcontext(&buff
,SH_JMPEVAL
);
484 buff
.olist
= pp
->olist
;
485 jmpval
= sigsetjmp(buff
.buff
,0);
490 lineno
= shp
->inlineno
;
491 if(traceon
=sh_isoption(SH_XTRACE
))
492 sh_offoption(SH_XTRACE
);
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))
497 if(!(mode
&SH_READEVAL
))
502 mode
&= ~SH_READEVAL
;
503 if(!sh_isoption(SH_VERBOSE
))
504 sh_offstate(SH_VERBOSE
);
505 if((mode
&~SH_FUNEVAL
) && shp
->hist_ptr
)
507 hist_flush(shp
->hist_ptr
);
508 mode
= sh_state(SH_INTERACTIVE
);
510 sh_exec(t
,sh_isstate(SH_ERREXIT
)|sh_isstate(SH_NOFORK
)|(mode
&~SH_FUNEVAL
));
511 if(!(mode
&SH_FUNEVAL
))
514 sh_popcontext(&buff
);
515 shp
->binscript
= binscript
;
517 sh_onoption(SH_XTRACE
);
519 shp
->inlineno
= lineno
;
523 shp
->st
.staklist
= saveslp
;
525 if(jmpval
>SH_JMPEVAL
)
526 siglongjmp(*shp
->jmplist
,jmpval
);
527 return(shp
->exitval
);
531 static int pipe_exec(Shell_t
* shp
,int pv
[], Shnode_t
*t
, int errorflg
)
534 register Shnode_t
*tchild
= t
->fork
.forktre
;
537 volatile Sfio_t
*iop
;
539 if((tchild
->tre
.tretyp
&COMMSK
)!=TCOM
|| !(np
=(Namval_t
*)(tchild
->com
.comnamp
)))
542 return(sh_exec(t
,errorflg
));
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);
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);
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
);
572 siglongjmp(*shp
->jmplist
,jmpval
);
575 #endif /* SHOPT_FASTPIPE */
578 * returns 1 when option -<c> is specified
580 static int checkopt(char *argv
[], int c
)
587 if(*cp
!='-' || cp
[1]=='-')
591 if(*cp
=='h' && cp
[1]==0 && *++argv
==0)
597 static void free_list(struct openlist
*olist
)
599 struct openlist
*item
,*next
;
600 for(item
=olist
;item
;item
=next
)
608 * set ${.sh.name} and ${.sh.subscript}
609 * set _ to reference for ${.sh.name}[$.sh.subscript]
611 static int set_instance(Shell_t
*shp
,Namval_t
*nq
, Namval_t
*node
, struct Namref
*nr
)
613 char *sp
=0,*cp
= nv_name(nq
);
615 memset(nr
,0,sizeof(*nr
));
617 nr
->root
= sh
.var_tree
;
618 nr
->table
= sh
.last_table
;
620 if((ap
=nv_arrayptr(nq
)) && (sp
= nv_getsub(nq
)))
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
;
633 nv_putval(SH_SUBSCRNOD
,nr
->sub
=sp
,NV_NOFREE
);
634 return(ap
->nelem
&ARRAY_SCAN
);
639 static void unset_instance(Namval_t
*nq
, Namval_t
*node
, struct Namref
*nr
,long mode
)
641 L_ARGNOD
->nvalue
.nrp
= node
->nvalue
.nrp
;
642 L_ARGNOD
->nvflag
= node
->nvflag
;
643 L_ARGNOD
->nvfun
= node
->nvfun
;
646 nv_putsub(nq
, nr
->sub
, mode
);
647 free((void*)nr
->sub
);
649 nv_unset(SH_NAMENOD
);
650 nv_unset(SH_SUBSCRNOD
);
653 int sh_exec(register const Shnode_t
*t
, int flags
)
655 register Shell_t
*shp
= &sh
;
656 Stk_t
*stkp
= shp
->stk
;
658 if(t
&& !shp
->st
.execbrk
&& !sh_isoption(SH_NOEXEC
))
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
));
671 int topfd
= shp
->topfd
;
672 char *sav
=stkptr(stkp
,0);
673 char *cp
=0, **com
=0, *comn
;
676 int was_interactive
= 0;
677 int was_errexit
= sh_isstate(SH_ERREXIT
);
678 int was_monitor
= sh_isstate(SH_MONITOR
);
680 if(flags
&sh_state(SH_INTERACTIVE
))
686 flags
&= ~sh_state(SH_INTERACTIVE
);
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
;
696 shp
->oldexit
=shp
->exitval
;
704 register struct argnod
*argp
;
706 Namval_t
*np
, *nq
, *last_table
;
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
);
715 if(t
->tre
.tretyp
&COMSCAN
)
717 argp
= t
->com
.comarg
;
718 if(argp
&& *com
&& !(argp
->argflag
&ARG_RAW
))
721 np
= (Namval_t
*)(t
->com
.comnamp
);
722 nq
= (Namval_t
*)(t
->com
.comnamq
);
725 while(np
==SYSCOMMAND
)
727 register int n
= b_command(0,com
,&shp
->bltindata
);
732 if(!(com0
= *(com
+=n
)))
734 np
= nv_bfsearch(com0
, shp
->bltin_tree
, &nq
, &cp
);
738 shp
->xargmin
-= command
;
739 shp
->xargmax
-= command
;
744 if(!command
&& np
&& is_abuiltin(np
))
745 np
= dtsearch(shp
->fun_tree
,np
);
748 if(!np
&& !strchr(com0
,'/'))
750 Dt_t
*root
= command
?shp
->bltin_tree
:shp
->fun_tree
;
751 np
= nv_bfsearch(com0
, root
, &nq
, &cp
);
753 if(shp
->namespace && !nq
&& !cp
)
755 int offset
= stktell(stkp
);
756 sfputr(stkp
,nv_name(shp
->namespace),-1);
759 stkseek(stkp
,offset
);
760 np
= nv_bfsearch(stkptr(stkp
,offset
), root
, &nq
, &cp
);
762 #endif /* SHOPT_NAMESPACE */
767 if(shp
->envlist
= argp
= t
->com
.comset
)
769 if(argn
==0 || (np
&& nv_isattr(np
,BLT_SPC
)))
774 if(checkopt(com
,'A'))
776 else if(checkopt(com
,'a'))
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
)
786 sh_scope(shp
,(struct argnod
*)0,0);
787 shp
->st
.var_local
= shp
->var_tree
;
791 if(np
==SYSTYPESET
|| np
==SYSLOCAL
)
793 if(np
==SYSTYPESET
|| (np
&& np
->nvalue
.bfp
==SYSTYPESET
->nvalue
.bfp
))
801 if(checkopt(com
,'C'))
803 if(checkopt(com
,'S'))
805 if(checkopt(com
,'n'))
807 else if(!shp
->typeinit
&& (checkopt(com
,'L') || checkopt(com
,'R') || checkopt(com
,'Z')))
810 else if(argn
>=3 && checkopt(com
,'T'))
812 shp
->prefix
= NV_CLASS
;
816 #endif /* SHOPT_TYPEDEF */
817 if((shp
->fn_depth
&& !shp
->prefix
) || np
==SYSLOCAL
)
820 else if(np
==SYSEXPORT
)
822 if(flgs
&(NV_EXPORT
|NV_NOREF
))
830 nv_setlist(argp
,flgs
,tp
);
831 if(np
==shp
->typeinit
)
837 last_table
= shp
->last_table
;
842 static char *argv
[1];
844 if(np
&& nv_isattr(np
,BLT_DCL
))
848 /* fake 'true' built-in */
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
))
858 int ison
= sh_isoption(SH_XTRACE
);
860 sh_onoption(SH_XTRACE
);
861 sh_trace(com
-command
,tflags
);
863 sh_redirect(shp
,io
,SH_SHOWME
);
865 sh_offoption(SH_XTRACE
);
868 if(trap
=shp
->st
.trap
[SH_DEBUGTRAP
])
870 int n
= sh_debug(shp
,trap
,(char*)0,(char*)0, com
, ARG_RAW
);
871 if(n
==255 && shp
->fn_depth
+shp
->dot_depth
)
884 sfsync(shp
->outpool
);
886 if(!np
&& !strchr(com0
,'/'))
888 if(path_search(com0
,NIL(Pathcomp_t
**),1))
890 error_info
.line
= t
->com
.comline
-shp
->st
.firstline
;
891 if((np
=nv_search(com0
,shp
->fun_tree
,0)) && !np
->nvalue
.ip
)
893 Namval_t
*mp
=nv_search(com0
,shp
->bltin_tree
,0);
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);
911 /* check for builtins */
912 if(np
&& is_abuiltin(np
))
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;
920 unsigned long was_vi
=0, was_emacs
=0, was_gmacs
=0;
922 bp
= &shp
->bltindata
;
924 save_data
= bp
->data
;
925 memset(&statb
, 0, sizeof(struct stat
));
926 if(strchr(nv_name(np
),'/'))
929 * disable editors for built-in
930 * versions of commands on PATH
932 was_vi
= sh_isoption(SH_VI
);
933 was_emacs
= sh_isoption(SH_EMACS
);
934 was_gmacs
= sh_isoption(SH_GMACS
);
936 sh_offoption(SH_EMACS
);
937 sh_offoption(SH_GMACS
);
940 sh_onstate(SH_NOFORK
);
941 sh_pushcontext(&buff
,SH_JMPCMD
);
942 jmpval
= sigsetjmp(buff
.buff
,1);
945 if(!(nv_isattr(np
,BLT_ENV
)))
946 error_info
.flags
|= ERROR_SILENT
;
947 errorpush(&buff
.err
,0);
950 struct openlist
*item
;
956 type
= (execflg
&& !shp
->subshell
&& !shp
->st
.trapcom
[0]);
957 sh_redirect(shp
,io
,type
);
958 for(item
=buff
.olist
;item
;item
=item
->next
)
961 if(!(nv_isattr(np
,BLT_ENV
)))
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
;
981 sh_scope(shp
,argp
,0);
983 opt_info
.index
= opt_info
.offset
= 0;
985 error_info
.id
= *com
;
988 shp
->bltinfun
= funptr(np
);
991 bp
->ptr
= nv_context(np
);
992 bp
->data
= t
->com
.comstate
;
995 bp
->flags
= (OPTIMIZE
!=0);
996 if(shp
->subshell
&& nv_isattr(np
,BLT_NOSFIO
))
998 if(execflg
&& !shp
->subshell
&&
999 !shp
->st
.trapcom
[0] && !shp
->st
.trap
[SH_ERRTRAP
] && shp
->fn_depth
==0 && !nv_isattr(np
,BLT_ENV
))
1001 /* do close-on-exec */
1003 for(fd
=0; fd
< shp
->lim
.open_max
; fd
++)
1004 if((shp
->fdstatus
[fd
]&IOCLEX
)&&fd
!=shp
->infd
)
1008 shp
->exitval
= (*shp
->bltinfun
)(argn
,com
,(void*)bp
);
1009 if(error_info
.flags
&ERROR_INTERACTIVE
)
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
;
1018 struct openlist
*item
;
1019 for(item
=buff
.olist
;item
;item
=item
->next
)
1023 sfclrlock(item
->strm
);
1024 if(shp
->hist_ptr
&& item
->strm
== shp
->hist_ptr
->histfp
)
1025 hist_close(shp
->hist_ptr
);
1027 sfclose(item
->strm
);
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
))
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
)))
1042 if(bp
->nosfio
&& shp
->pwd
)
1046 /* restore directory changed */
1047 if(statb
.st_ino
!=stata
.st_ino
|| statb
.st_dev
!=stata
.st_dev
)
1050 sh_offstate(SH_STOPOK
);
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
;
1058 sh_popcontext(&buff
);
1059 errorpop(&buff
.err
);
1060 error_info
.flags
&= ~(ERROR_SILENT
|ERROR_NOTIFY
);
1063 free_list(buff
.olist
);
1067 sh_onoption(SH_EMACS
);
1069 sh_onoption(SH_GMACS
);
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
);
1078 siglongjmp(*shp
->jmplist
,jmpval
);
1081 ((Shnode_t
*)t
)->com
.comset
= 0;
1083 if(shp
->exitval
>=0)
1088 /* check for functions */
1089 if(!command
&& np
&& nv_isattr(np
,NV_FUNCTION
))
1093 struct checkpt buff
;
1097 register struct slnod
*slp
;
1100 indx
= path_search(com0
,NIL(Pathcomp_t
**),0);
1102 np
= nv_search(com0
,shp
->fun_tree
,HASH_NOSCOPE
);
1108 errormsg(SH_DICT
,ERROR_exit(0),e_defined
,com0
);
1109 shp
->exitval
= ERROR_NOEXEC
;
1113 errormsg(SH_DICT
,ERROR_exit(0),e_found
,"function");
1114 shp
->exitval
= ERROR_NOENT
;
1119 /* increase refcnt for unset */
1120 slp
= (struct slnod
*)np
->nvenv
;
1121 sh_funstaks(slp
->slchild
,1);
1122 staklink(slp
->slptr
);
1125 shp
->last_table
= last_table
;
1126 mode
= set_instance(shp
,nq
,&node
,&nr
);
1131 sh_pushcontext(&buff
,SH_JMPCMD
);
1132 jmpval
= sigsetjmp(buff
.buff
,0);
1137 indx
= sh_redirect(shp
,io
,execflg
);
1138 sh_funct(shp
,np
,argn
,com
,t
->com
.comset
,(flags
&~OPTIMIZE_FLAG
));
1143 free_list(buff
.olist
);
1144 sh_popcontext(&buff
);
1145 sh_iorestore(shp
,indx
,jmpval
);
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
);
1165 register pid_t parent
;
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
))
1182 if(sh_isstate(SH_PROFILE
) || shp
->dot_depth
)
1184 /* disable foreground job monitor */
1186 sh_offstate(SH_MONITOR
);
1188 else if(!(type
&FINT
))
1189 sh_offstate(SH_MONITOR
);
1190 #endif /* SHOPT_DEVFD */
1193 job
.parent
=parent
=0;
1198 if(((type
&(FAMP
|FINT
)) == (FAMP
|FINT
)) && (maxjob
=nv_getnum(JOBMAXNOD
))>0)
1200 while(job
.numbjob
>= maxjob
)
1207 #endif /* SHOPT_BGX */
1209 coproc_init(shp
,pipes
);
1212 if((type
&(FAMP
|FINT
)) == (FAMP
|FINT
))
1213 parent
= sh_ntfork(shp
,t
,com
,&jobid
,ntflag
);
1215 parent
= sh_fork(type
,&jobid
);
1222 parent
= sh_ntfork(shp
,t
,com
,&jobid
,ntflag
);
1224 parent
= sh_fork(type
,&jobid
);
1226 if((parent
= sh_ntfork(shp
,t
,com
,&jobid
,ntflag
))<=0)
1228 # endif /* _lib_fork */
1232 parent
= sh_fork(type
,&jobid
);
1233 #endif /* SHOPT_SPAWN */
1236 if(job
.parent
=parent
)
1237 /* This is the parent branch of fork
1238 * It may or may not wait for the child
1247 sh_close(shp
->inpipe
[0]);
1248 if(type
&(FCOOP
|FAMP
))
1249 shp
->bckpid
= parent
;
1250 else if(!(type
&(FAMP
|FPOU
)))
1252 if(shp
->topfd
> topfd
)
1253 sh_iorestore(shp
,topfd
,0);
1254 if(!sh_isoption(SH_MONITOR
))
1256 if(!(shp
->sigflag
[SIGINT
]&(SH_SIGFAULT
|SH_SIGOFF
)))
1258 shp
->trapnote
|= SH_SIGIGNORE
;
1260 if(execflg
&& shp
->subshell
&& !shp
->subshare
)
1263 job
.pwlist
->p_env
--;
1265 else if(shp
->pipepid
)
1266 shp
->pipepid
= parent
;
1269 if(!sh_isoption(SH_MONITOR
))
1271 shp
->trapnote
&= ~SH_SIGIGNORE
;
1272 if(shp
->exitval
== (SH_EXITSIG
|SIGINT
))
1278 if(sh_isstate(SH_PROFILE
) || sh_isstate(SH_INTERACTIVE
))
1280 /* print job number */
1282 sfprintf(sfstderr
,"[%d]\t%d\n",jobid
,parent
);
1284 sfprintf(sfstderr
,"%d\n",parent
);
1292 * this is the FORKED branch (child) of execute
1295 volatile int jmpval
;
1296 struct checkpt buff
;
1299 sh_pushcontext(&buff
,SH_JMPEXIT
);
1300 jmpval
= sigsetjmp(buff
.buff
,0);
1303 if((type
&FINT
) && !sh_isstate(SH_MONITOR
))
1305 /* default std input for & */
1306 signal(SIGINT
,SIG_IGN
);
1307 signal(SIGQUIT
,SIG_IGN
);
1311 sh_chkopen(e_devnull
);
1314 sh_offstate(SH_MONITOR
);
1315 /* pipe in or out */
1317 if((type
&FAMP
) && sh_isoption(SH_BGNICE
))
1319 #endif /* _lib_nice */
1322 sh_iorenumber(shp
,shp
->inpipe
[0],0);
1323 if(!(type
&FPOU
) || (type
&FCOOP
))
1324 sh_close(shp
->inpipe
[1]);
1328 sh_iorenumber(shp
,shp
->outpipe
[1],1);
1329 sh_pclose(shp
->outpipe
);
1331 if((type
&COMMSK
)!=TCOM
)
1332 error_info
.line
= t
->fork
.forkline
-shp
->st
.firstline
;
1336 sh_redirect(shp
,t
->tre
.treio
,1);
1337 if(shp
->topfd
> topfd
)
1340 while((parent
= vfork()) < 0)
1341 _sh_fork(parent
, 0, (int*)0);
1348 sh_iorestore(shp
,topfd
,SH_JMPCMD
);
1349 sh_done(shp
,(shp
->exitval
&SH_EXITSIG
)?(shp
->exitval
&SH_EXITMASK
):0);
1353 if((type
&COMMSK
)!=TCOM
)
1355 /* don't clear job table for out
1356 pipes so that jobs comand can
1357 be used in a pipeline
1359 if(!no_fork
&& !(type
&FPOU
))
1361 sh_exec(t
->fork
.forktre
,flags
|sh_state(SH_NOFORK
)|sh_state(SH_FORKED
));
1365 sh_offoption(SH_ERREXIT
);
1367 path_exec(com0
,com
,t
->com
.comset
);
1370 sh_popcontext(&buff
);
1371 if(jmpval
>SH_JMPEXIT
)
1372 siglongjmp(*shp
->jmplist
,jmpval
);
1380 * don't create a new process, just
1381 * save and restore io-streams
1384 int jmpval
, waitall
;
1385 int simple
= (t
->fork
.forktre
->tre
.tretyp
&COMMSK
)==TCOM
;
1386 struct checkpt buff
;
1389 sh_pushcontext(&buff
,SH_JMPIO
);
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);
1398 * if read end of pipe is a simple command
1399 * treat as non-sharable to improve performance
1402 sfset(sfstdin
,SF_PUBLIC
|SF_SHARE
,0);
1403 waitall
= job
.waitall
;
1408 error_info
.line
= t
->fork
.forkline
-shp
->st
.firstline
;
1409 jmpval
= sigsetjmp(buff
.buff
,0);
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
);
1417 sfsync(shp
->outpool
);
1418 sh_popcontext(&buff
);
1419 sh_iorestore(shp
,buff
.topfd
,jmpval
);
1421 free_list(buff
.olist
);
1424 job
.waitall
= waitall
;
1425 type
= shp
->exitval
;
1426 if(!(type
&SH_EXITSIG
))
1428 /* wait for remainder of pipline */
1431 job_wait(shp
->pipepid
);
1432 type
= shp
->exitval
;
1435 job_wait(waitall
?pid
:0);
1436 if(type
|| !sh_isoption(SH_PIPEFAIL
))
1437 shp
->exitval
= type
;
1441 if(simple
&& was_errexit
)
1444 sh_onstate(SH_ERREXIT
);
1448 siglongjmp(*shp
->jmplist
,jmpval
);
1454 flags
&= ~OPTIMIZE_FLAG
;
1455 if(!shp
->subshell
&& !shp
->st
.trapcom
[0] && !shp
->st
.trap
[SH_ERRTRAP
] && (flags
&sh_state(SH_NOFORK
)))
1459 struct checkpt buff
;
1460 shp
->st
.otrapcom
= 0;
1461 if((nsig
=shp
->st
.trapmax
*sizeof(char*))>0 || shp
->st
.trapcom
[0])
1463 nsig
+= sizeof(char*);
1464 memcpy(savsig
=malloc(nsig
),(char*)&shp
->st
.trapcom
[0],nsig
);
1465 shp
->st
.otrapcom
= (char**)savsig
;
1468 sh_pushcontext(&buff
,SH_JMPEXIT
);
1469 jmpval
= sigsetjmp(buff
.buff
,0);
1471 sh_exec(t
->par
.partre
,flags
);
1472 sh_popcontext(&buff
);
1473 if(jmpval
> SH_JMPEXIT
)
1474 siglongjmp(*shp
->jmplist
,jmpval
);
1478 sh_subshell(t
->par
.partre
,flags
,0);
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
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
;
1504 if(sh_isoption(SH_PIPEFAIL
))
1507 job
.waitall
|= !pipejob
&& sh_isstate(SH_MONITOR
);
1512 type
= pipe_exec(shp
,pvn
,t
->lst
.lstlef
, errorflg
);
1514 /* create the pipe */
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 */
1521 /* save the pipe stream-ids */
1523 /* close out-part of pipe */
1525 /* pipeline all in one process group */
1528 /* repeat until end of pipeline */
1529 while(!type
&& t
->tre
.tretyp
==TFIL
);
1536 * execute last element of pipeline
1537 * in the current process
1539 ((Shnode_t
*)t
)->tre
.tretyp
|= showme
;
1543 /* execution failure, close pipe */
1549 if(!pipejob
&& sh_isstate(SH_MONITOR
))
1550 tcsetpgrp(JOBTTY
,shp
->pid
);
1552 job
.curpgid
= savepgid
;
1558 /* a list of commands are executed here */
1561 sh_exec(t
->lst
.lstlef
,errorflg
|OPTIMIZE
);
1564 while(t
->tre
.tretyp
== TLST
);
1572 if(sh_exec(t
->lst
.lstlef
,OPTIMIZE
)==0)
1573 sh_exec(t
->lst
.lstrit
,flags
);
1579 if(sh_exec(t
->lst
.lstlef
,OPTIMIZE
)!=0)
1580 sh_exec(t
->lst
.lstrit
,flags
);
1583 case TFOR
: /* for and select */
1585 register char **args
;
1587 register Namval_t
*np
;
1588 int flag
= errorflg
|OPTIMIZE_FLAG
;
1589 struct dolnod
*argsav
=0;
1591 char *cp
, *trap
, *nullptr = 0;
1592 int nameref
, refresh
=1;
1595 int jmpval
= ((struct checkpt
*)shp
->jmplist
)->mode
;
1596 struct checkpt buff
;
1597 void *optlist
= shp
->optlist
;
1599 sh_tclear(t
->for_
.fortre
);
1600 sh_pushcontext(&buff
,jmpval
);
1601 jmpval
= sigsetjmp(buff
.buff
,0);
1604 #endif /* SHOPT_OPTIMIZE */
1605 error_info
.line
= t
->for_
.forline
-shp
->st
.firstline
;
1606 if(!(tp
=t
->for_
.forlst
))
1608 args
=shp
->st
.dolv
+1;
1609 nargs
= shp
->st
.dolc
;
1610 argsav
=sh_arguse(shp
);
1614 args
=sh_argbuild(shp
,&argn
,tp
,0);
1617 np
= nv_open(t
->for_
.fornam
, shp
->var_tree
,NV_NOASSIGN
|NV_NOARRAY
|NV_VARNAME
|NV_NOREF
);
1618 nameref
= nv_isref(np
)!=0;
1621 while(cp
&& shp
->st
.execbrk
==0)
1623 if(t
->tre
.tretyp
&COMSCAN
)
1627 /* reuse register */
1630 sh_menu(sfstderr
,nargs
,args
);
1633 save_prompt
= shp
->nextprompt
;
1634 shp
->nextprompt
= 3;
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
))
1643 if(!(val
=nv_getval(sh_scoped(shp
,REPLYNOD
))))
1653 if(type
< '0' && type
> '9')
1658 type
= (int)strtol(val
, (char**)0, 10)-1;
1659 if(type
<0 || type
>= nargs
)
1666 nv_offattr(np
,NV_REF
);
1667 else if(nv_isattr(np
, NV_ARRAY
))
1668 nv_putsub(np
,NIL(char*),0L);
1671 nv_setref(np
,(Dt_t
*)0,NV_VARNAME
);
1672 if(trap
=shp
->st
.trap
[SH_DEBUGTRAP
])
1674 av
[0] = (t
->tre
.tretyp
&COMSCAN
)?"select":"for";
1675 av
[1] = t
->for_
.fornam
;
1679 sh_debug(shp
,trap
,(char*)0,(char*)0,av
,0);
1681 sh_exec(t
->for_
.fortre
,flag
);
1682 flag
&= ~OPTIMIZE_FLAG
;
1683 if(t
->tre
.tretyp
&COMSCAN
)
1685 if((cp
=nv_getval(sh_scoped(shp
,REPLYNOD
))) && *cp
==0)
1691 if(shp
->st
.breakcnt
<0)
1692 shp
->st
.execbrk
= (++shp
->st
.breakcnt
!=0);
1696 sh_popcontext(&buff
);
1697 sh_tclear(t
->for_
.fortre
);
1698 sh_optclear(shp
,optlist
);
1700 siglongjmp(*shp
->jmplist
,jmpval
);
1701 #endif /*SHOPT_OPTIMIZE */
1702 if(shp
->st
.breakcnt
>0)
1703 shp
->st
.execbrk
= (--shp
->st
.breakcnt
!=0);
1705 sh_argfree(shp
,argsav
,0);
1710 case TWH
: /* while and until */
1713 int first
= OPTIMIZE_FLAG
;
1714 Shnode_t
*tt
= t
->wh
.whtre
;
1718 #endif /*SHOPT_FILESCAN*/
1720 int jmpval
= ((struct checkpt
*)shp
->jmplist
)->mode
;
1721 struct checkpt buff
;
1722 void *optlist
= shp
->optlist
;
1724 sh_tclear(t
->wh
.whtre
);
1725 sh_tclear(t
->wh
.dotre
);
1726 sh_pushcontext(&buff
,jmpval
);
1727 jmpval
= sigsetjmp(buff
.buff
,0);
1730 #endif /* SHOPT_OPTIMIZE */
1732 if(type
==TWH
&& tt
->tre
.tretyp
==TCOM
&& !tt
->com
.comarg
&& tt
->com
.comio
)
1734 fd
= sh_redirect(shp
,tt
->com
.comio
,3);
1738 iop
= sfnew(NULL
,NULL
,SF_UNBOUND
,fd
,SF_READ
);
1740 open("/dev/null",O_RDONLY
);
1741 shp
->offsets
[0] = -1;
1742 shp
->offsets
[1] = 0;
1744 nv_setlist(tt
->com
.comset
,NV_IDENT
|NV_ASSIGN
,0);
1746 #endif /*SHOPT_FILESCAN */
1748 while(shp
->st
.execbrk
==0)
1753 if(!(shp
->cur_line
=sfgetr(iop
,'\n',SF_STRING
)))
1757 #endif /*SHOPT_FILESCAN */
1758 if((sh_exec(tt
,first
)==0)!=(type
==TWH
))
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
);
1767 errorflg
&= ~OPTIMIZE_FLAG
;
1769 shp
->offsets
[0] = -1;
1770 shp
->offsets
[1] = 0;
1771 #endif /*SHOPT_FILESCAN */
1775 sh_popcontext(&buff
);
1776 sh_tclear(t
->wh
.whtre
);
1777 sh_tclear(t
->wh
.dotre
);
1778 sh_optclear(shp
,optlist
);
1780 siglongjmp(*shp
->jmplist
,jmpval
);
1781 #endif /*SHOPT_OPTIMIZE */
1782 if(shp
->st
.breakcnt
>0)
1783 shp
->st
.execbrk
= (--shp
->st
.breakcnt
!=0);
1794 #endif /*SHOPT_FILESCAN */
1797 case TARITH
: /* (( expression )) */
1799 register char *trap
;
1801 error_info
.line
= t
->ar
.arline
-shp
->st
.firstline
;
1803 if(!(t
->ar
.arexpr
->argflag
&ARG_RAW
))
1804 arg
[1] = sh_macpat(shp
,t
->ar
.arexpr
,OPTIMIZE
|ARG_ARITH
);
1806 arg
[1] = t
->ar
.arexpr
->argval
;
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
))
1813 sh_trace(NIL(char**),0);
1814 sfprintf(sfstderr
,"((%s))\n",arg
[1]);
1817 shp
->exitval
= !arith_exec((Arith_t
*)t
->ar
.arcomp
);
1819 shp
->exitval
= !sh_arith(arg
[1]);
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
);
1829 shp
->exitval
=0; /* force zero exit for if-then-fi */
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
])
1845 sh_debug(shp
,trap
, (char*)0, (char*)0, av
, 0);
1849 register struct argnod
*rex
=(struct argnod
*)t
->reg
.regptr
;
1853 if(rex
->argflag
&ARG_MAC
)
1855 s
= sh_macpat(shp
,rex
,OPTIMIZE
|ARG_EXP
);
1856 while(*s
=='\\' && s
[1]==0)
1861 type
= (rex
->argflag
&ARG_RAW
);
1862 if((type
&& strcmp(r
,s
)==0) ||
1863 (!type
&& (strmatch(r
,s
)
1866 do sh_exec(t
->reg
.regcom
,(t
->reg
.regflag
?0:flags
));
1867 while(t
->reg
.regflag
&&
1868 (t
=(Shnode_t
*)t
->reg
.regnxt
));
1876 t
=(Shnode_t
*)t
->reg
.regnxt
;
1883 /* time the command */
1884 struct tms before
,after
;
1885 const char *format
= e_timeformat
;
1888 struct timeval tb
,ta
;
1891 #endif /* timeofday */
1894 sh_exec(t
->par
.partre
,OPTIMIZE
);
1895 shp
->exitval
= !shp
->exitval
;
1901 timer_on
= sh_isstate(SH_TIMING
);
1906 bt
= times(&before
);
1907 #endif /* timeofday */
1909 sh_onstate(SH_TIMING
);
1910 sh_exec(t
->par
.partre
,OPTIMIZE
);
1912 sh_offstate(SH_TIMING
);
1919 #endif /* timeofday */
1920 before
.tms_utime
= before
.tms_cutime
= 0;
1921 before
.tms_stime
= before
.tms_cstime
= 0;
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);
1929 at
= times(&after
) - bt
;
1930 #endif /* timeofday */
1934 Namval_t
*np
= nv_open("TIMEFORMAT",shp
->var_tree
,NV_NOADD
);
1937 format
= nv_getval(np
);
1941 format
= e_timeformat
;
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
);
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;
1961 if(t
->tre
.tretyp
==TNSPACE
)
1963 Dt_t
*root
,*oldroot
, *top
=0;
1964 Namval_t
*oldnspace
= shp
->namespace;
1965 int offset
= stktell(stkp
);
1966 long optindex
= shp
->st
.optindex
;
1968 errormsg(SH_DICT
,ERROR_exit(1),e_ident
,fname
);
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
)))
1976 root
= dtopen(&_Nvdisc
,Dtoset
);
1977 nv_putval(np
,(char*)root
,NV_TABLE
|NV_NOFREE
);
1978 shp
->st
.optindex
= 1;
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
;
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
;
1994 dtview(top
,shp
->var_tree
);
1995 shp
->namespace = oldnspace
;
1996 shp
->st
.optindex
= optindex
;
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
)
2005 int offset
= stktell(stkp
);
2010 npv
= nv_open(cp
,shp
->var_tree
,NV_NOASSIGN
|NV_NOARRAY
|NV_VARNAME
);
2016 sfwrite(stkp
,fname
,cp
++-fname
);
2018 npv
= nv_open(stkptr(stkp
,offset
),shp
->var_tree
,NV_NOASSIGN
|NV_NOARRAY
|NV_VARNAME
);
2020 offset
= stktell(stkp
);
2021 sfprintf(stkp
,"%s.%s%c",nv_name(npv
),cp
,0);
2022 fname
= stkptr(stkp
,offset
);
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
);
2027 else if(shp
->namespace)
2029 int offset
= stktell(stkp
);
2030 sfputr(stkp
,nv_name(shp
->namespace),-1);
2032 sfputr(stkp
,fname
,0);
2033 fname
= stkptr(stkp
,offset
);
2035 #endif /* SHOPT_NAMESPACE */
2036 np
= nv_open(fname
,sh_subfuntree(1),NV_NOASSIGN
|NV_NOARRAY
|NV_VARNAME
|NV_NOSCOPE
);
2044 if(tp
=nv_open(shp
->typeinit
->nvname
,shp
->typedict
,NV_IDENT
|NV_NOFAIL
))
2049 cp
= nv_setdisc(tp
,cp
,np
,(Namfun_t
*)tp
);
2053 errormsg(SH_DICT
,ERROR_exit(1),e_baddisc
,fname
);
2057 slp
= (struct slnod
*)np
->nvenv
;
2058 sh_funstaks(slp
->slchild
,-1);
2059 stakdelete(slp
->slptr
);
2062 free((void*)np
->nvalue
.rp
);
2069 np
->nvalue
.rp
= new_of(struct Ufunction
,shp
->funload
?sizeof(Dtlink_t
):0);
2070 memset((void*)np
->nvalue
.rp
,0,sizeof(struct Ufunction
));
2072 if(t
->funct
.functstak
)
2074 static Dtdisc_t _Rpdisc
=
2076 offsetof(struct Ufunction
,fname
), -1, sizeof(struct Ufunction
)
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
);
2096 struct Ufunction
*rp
= np
->nvalue
.rp
;
2099 shp
->fpathdict
= dtopen(&_Rpdisc
,Dtbag
);
2101 dtinsert(shp
->fpathdict
,rp
);
2107 nv_onattr(np
,NV_FUNCTION
|NV_FPOSIX
);
2109 nv_onattr(np
,NV_FUNCTION
);
2111 nv_onattr(np
,NV_FTMP
);
2113 nv_onattr(np
,NV_OPTGET
);
2117 /* new test compound command */
2121 register char *left
;
2122 int negate
= (type
&TNEGATE
)!=0;
2125 error_info
.line
= t
->tst
.tstline
-shp
->st
.firstline
;
2127 if((type
&TPAREN
)==TPAREN
)
2129 sh_exec(t
->lst
.lstlef
,OPTIMIZE
);
2134 register int traceon
=0;
2135 register char *right
;
2136 register char *trap
;
2139 left
= sh_macpat(shp
,&(t
->lst
.lstlef
->arg
),OPTIMIZE
);
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
))
2146 traceon
= sh_trace(NIL(char**),0);
2147 sfwrite(sfstderr
,e_tstbegin
,(type
&TNEGATE
?5:3));
2152 sfprintf(sfstderr
,"-%c %s",n
,sh_fmtq(left
));
2163 sh_debug(shp
,trap
,(char*)0,(char*)0,argv
, 0);
2165 n
= test_unop(n
,left
);
2167 else if(type
&TBINARY
)
2172 op
= (char*)(shtab_testops
+(n
&037)-1)->sh_name
;
2174 if(type
==TEST_PEQ
|| type
==TEST_PNE
)
2183 sh_debug(shp
,trap
,(char*)0,(char*)0,argv
, pattern
);
2185 n
= test_binop(n
,left
,right
);
2188 sfprintf(sfstderr
,"%s %s ",sh_fmtq(left
),op
);
2190 out_pattern(sfstderr
,right
,-1);
2192 sfputr(sfstderr
,sh_fmtq(right
),-1);
2196 sfwrite(sfstderr
,e_tstend
,4);
2198 shp
->exitval
= ((!n
)^negate
);
2204 if(shp
->trapnote
|| (shp
->exitval
&& sh_isstate(SH_ERREXIT
)) &&
2208 if(mainloop
&& com0
)
2210 /* store last argument here if it fits */
2211 static char lastarg
[32];
2212 if(sh_isstate(SH_FORKED
))
2214 if(shp
->lastarg
!= lastarg
&& shp
->lastarg
)
2216 if(strlen(comn
) < sizeof(lastarg
))
2218 nv_onattr(L_ARGNOD
,NV_NOFREE
);
2219 shp
->lastarg
= strcpy(lastarg
,comn
);
2223 nv_offattr(L_ARGNOD
,NV_NOFREE
);
2224 shp
->lastarg
= strdup(comn
);
2231 if(sav
!= stkptr(stkp
,0))
2233 else if(stktell(stkp
))
2236 if(shp
->trapnote
&SH_SIGSET
)
2237 sh_exit(SH_EXITSIG
|shp
->lastsig
);
2239 sh_onstate(SH_INTERACTIVE
);
2240 if(was_monitor
&& sh_isoption(SH_MONITOR
))
2241 sh_onstate(SH_MONITOR
);
2243 sh_onstate(SH_ERREXIT
);
2245 return(shp
->exitval
);
2248 int sh_run(int argn
, char *argv
[])
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
;
2258 memset(t
, 0, sizeof(struct comnod
));
2259 dp
= (struct dolnod
*)stakalloc((unsigned)sizeof(struct dolnod
) + ARG_SPARE
*sizeof(char*) + argn
*sizeof(char*));
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
));
2268 sh
.bltindata
= bltindata
;
2269 if(savptr
!=stakptr(0))
2270 stakset(savptr
,savtop
);
2277 * test for equality with second argument trimmed
2278 * returns 1 if r == trim(s) otherwise 0
2281 static int trim_eq(register const char *r
,register const char *s
)
2295 * print out the command line if set -x is on
2298 int sh_trace(register char *argv
[], register int nl
)
2302 register int bracket
= 0;
2305 if(sh_isoption(SH_XTRACE
))
2307 /* make this trace atomic */
2308 sfset(sfstderr
,SF_SHARE
|SF_PUBLIC
,0);
2309 if(!(cp
=nv_getval(sh_scoped(shp
,PS4NOD
))))
2313 sh_offoption(SH_XTRACE
);
2314 cp
= sh_mactry(shp
,cp
);
2315 sh_onoption(SH_XTRACE
);
2318 sfputr(sfstderr
,cp
,-1);
2321 char *argv0
= *argv
;
2323 /* don't quote [ and [[ */
2324 if(*(cp
=argv
[0])=='[' && (!cp
[1] || !cp
[2]&&cp
[1]=='['))
2326 sfputr(sfstderr
,cp
,*++argv
?' ':nl
);
2331 if(bracket
==0 || *argv
|| *cp
!=']')
2333 if(decl
&& shp
->prefix
&& cp
!=argv0
&& *cp
!='-')
2335 if(*cp
=='.' && cp
[1]==0)
2338 sfputr(sfstderr
,shp
->prefix
,'.');
2340 sfputr(sfstderr
,cp
,*argv
?' ':nl
);
2342 sfset(sfstderr
,SF_SHARE
|SF_PUBLIC
,1);
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.
2362 static void timed_out(void *handle
)
2370 * called by parent and child after fork by sh_fork()
2372 pid_t
_sh_fork(register pid_t parent
,int flags
,int *jobid
)
2374 static long forkcnt
= 1000L;
2376 pid_t curpgid
= job
.curpgid
;
2377 pid_t postid
= (flags
&FAMP
)?0:curpgid
;
2382 if((forkcnt
*= 2) > 1000L*SH_FORKLIM
)
2385 errormsg(SH_DICT
,ERROR_system(ERROR_NOEXEC
),e_nofork
);
2387 timeout
= (void*)sh_timeradd(forkcnt
, 0, timed_out
, NIL(void*));
2388 nochild
= job_wait((pid_t
)1);
2393 else if(forkcnt
>1000L)
2403 int myjob
,waitall
=job
.waitall
;
2407 job
.waitall
= waitall
;
2409 /* first process defines process group */
2410 if(sh_isstate(SH_MONITOR
))
2413 * errno==EPERM means that an earlier processes
2414 * completed. Make parent the job group id.
2417 job
.curpgid
= parent
;
2418 if(job
.jobcontrol
|| (flags
&FAMP
))
2420 if(setpgid(parent
,job
.curpgid
)<0 && errno
==EPERM
)
2421 setpgid(parent
,parent
);
2425 if(!sh_isstate(SH_MONITOR
) && job
.waitall
&& postid
==0)
2426 job
.curpgid
= parent
;
2430 if(!postid
&& (flags
&(FAMP
|FINT
)) == (FAMP
|FINT
))
2432 myjob
= job_post(parent
,postid
);
2436 myjob
= job_post(parent
,postid
);
2437 #endif /* SHOPT_BGX */
2439 job
.curpgid
= curpgid
;
2447 /* This is the child process */
2448 if(shp
->trapnote
&SH_SIGTERM
)
2449 sh_exit(SH_EXITSIG
|SIGTERM
);
2451 timerdel(NIL(void*));
2453 if(!job
.jobcontrol
&& !(flags
&FAMP
))
2454 sh_offstate(SH_MONITOR
);
2455 if(sh_isstate(SH_MONITOR
))
2459 job
.curpgid
= parent
;
2460 while(setpgid(0,job
.curpgid
)<0 && job
.curpgid
!=parent
)
2461 job
.curpgid
= parent
;
2463 if(job
.curpgid
==parent
&& !(flags
&FAMP
))
2464 tcsetpgrp(job
.fd
,job
.curpgid
);
2465 # endif /* SIGTSTP */
2470 signal(SIGTTIN
,SIG_DFL
);
2471 signal(SIGTTOU
,SIG_DFL
);
2472 signal(SIGTSTP
,SIG_DFL
);
2474 # endif /* SIGTSTP */
2479 sh_offoption(SH_LOGIN_SHELL
);
2480 sh_onstate(SH_FORKED
);
2481 sh_onstate(SH_NOLOG
);
2483 shp
->fn_depth
= shp
->fn_reset
= 0;
2486 #endif /* SHOPT_ACCT */
2487 /* Reset remaining signals to parent */
2488 /* except for those `lost' by trap */
2489 if(!(flags
&FSHOWME
))
2492 if((flags
&FAMP
) && shp
->coutpipe
>1)
2493 sh_close(shp
->coutpipe
);
2502 pid_t
sh_fork(int flags
, int *jobid
)
2504 register pid_t parent
;
2507 if(sffileno(sfstdin
)<0)
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);
2514 sfseek(sfstdin
,current
,SEEK_SET
);
2516 #endif /* SHOPT_FASTPIPE */
2519 sfsync(NIL(Sfio_t
*));
2520 sh
.trapnote
&= ~SH_SIGTERM
;
2523 while(_sh_fork(parent
=fork(),flags
,jobid
) < 0);
2524 sh_stats(STAT_FORKS
);
2534 * add exports from previous scope to the new scope
2536 static void local_exports(register Namval_t
*np
, void *data
)
2538 register Namval_t
*mp
;
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);
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.
2551 int sh_funscope(int argn
, char *argv
[],int(*fun
)(void*),void *arg
,int execflg
)
2553 register char *trap
;
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;
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
;
2570 shp
->options
= shp
->glob_options
;
2572 shp
->st
.lineno
= error_info
.line
;
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;
2584 fp
= (struct funenv
*)arg
;
2585 shp
->st
.real_fun
= (fp
->node
)->nvalue
.rp
;
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))
2592 /* eliminate parent scope */
2593 nv_scan(prevscope
->save_tree
, local_exports
,(void*)0, NV_EXPORT
, NV_EXPORT
|NV_NOSCOPE
);
2595 shp
->st
.save_tree
= shp
->var_tree
;
2599 if(nv_isattr(fp
->node
,NV_TAGGED
))
2600 sh_onoption(SH_XTRACE
);
2602 sh_offoption(SH_XTRACE
);
2604 if((np
=(fp
->node
)->nvalue
.rp
->nspace
) && np
!=shp
->namespace)
2606 Dt_t
*dt
= shp
->var_tree
;
2608 dtview(dt
,nv_dict(np
));
2609 shp
->var_tree
= nv_dict(np
);
2610 shp
->namespace = np
;
2612 #endif /* SHOPT_NAMESPACE */
2614 shp
->st
.cmdname
= argv
[0];
2615 /* save trap table */
2616 if((nsig
=shp
->st
.trapmax
*sizeof(char*))>0 || shp
->st
.trapcom
[0])
2618 nsig
+= sizeof(char*);
2619 memcpy(savstak
=stakalloc(nsig
),(char*)&shp
->st
.trapcom
[0],nsig
);
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);
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
);
2637 if(shp
->fn_depth
++ > MAXDEPTH
)
2640 siglongjmp(*shp
->jmplist
,SH_JMPERRFN
);
2646 sh_exec((Shnode_t
*)(nv_funtree((fp
->node
))),execflg
|SH_ERREXIT
);
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
;
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;
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
));
2670 memcpy((char*)&shp
->st
.trapcom
[0],savstak
,nsig
);
2674 shp
->options
= options
;
2675 shp
->last_root
= last_root
;
2676 if(jmpval
== SH_JMPSUB
)
2677 siglongjmp(*shp
->jmplist
,jmpval
);
2683 if(shp
->exitval
> SH_EXITSIG
)
2684 sh_fault(shp
->exitval
&SH_EXITMASK
);
2685 if(jmpval
> SH_JMPFUN
)
2688 siglongjmp(*shp
->jmplist
,jmpval
);
2693 static void sh_funct(Shell_t
*shp
,Namval_t
*np
,int argn
, char *argv
[],struct argnod
*envlist
,int execflg
)
2696 char *fname
= nv_getval(SH_FUNNAMENOD
);
2697 struct Level
*lp
=(struct Level
*)(SH_LEVELNOD
->nvfun
);
2698 int level
, pipepid
=shp
->pipepid
;
2700 sh_stats(STAT_FUNCT
);
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
))
2711 int loopcnt
= shp
->st
.loopcnt
;
2712 shp
->posix_fun
= np
;
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
;
2728 sh_funscope(argn
,argv
,0,&fun
,execflg
);
2730 if(level
-- != nv_getnum(SH_LEVELNOD
))
2732 Shscope_t
*sp
= sh_getscope(0,SEEK_END
);
2735 lp
->maxlevel
= level
;
2736 SH_LEVELNOD
->nvalue
.s
= lp
->maxlevel
;
2738 nv_putval(SH_FUNNAMENOD
,shp
->st
.funname
,NV_NOFREE
);
2740 nv_putval(SH_FUNNAMENOD
,fname
,NV_NOFREE
);
2742 nv_putval(SH_PATHNAMENOD
,shp
->st
.filename
,NV_NOFREE
);
2743 shp
->pipepid
= pipepid
;
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
2751 int sh_fun(Namval_t
*np
, Namval_t
*nq
, char *argv
[])
2754 register int offset
;
2755 register char *base
;
2759 char *prefix
= shp
->prefix
;
2764 if((offset
=staktell())>0)
2772 argv
[0] = nv_name(np
);
2776 mode
= set_instance(shp
,nq
,&node
, &nr
);
2780 struct checkpt buff
;
2781 Shbltin_t
*bp
= &sh
.bltindata
;
2782 sh_pushcontext(&buff
,SH_JMPCMD
);
2783 jmpval
= sigsetjmp(buff
.buff
,1);
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;
2793 sh
.exitval
= (*funptr(np
))(n
,argv
,(void*)bp
);
2795 sh_popcontext(&buff
);
2796 if(jmpval
>SH_JMPCMD
)
2797 siglongjmp(*sh
.jmplist
,jmpval
);
2800 sh_funct(shp
,np
,n
,argv
,(struct argnod
*)0,sh_isstate(SH_ERREXIT
));
2802 unset_instance(nq
, &node
, &nr
, mode
);
2805 stakset(base
,offset
);
2806 shp
->prefix
= prefix
;
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
2815 int cmdrecurse(int argc
, char* argv
[], int ac
, char* av
[])
2825 * set up pipe for cooperating process
2827 static void coproc_init(Shell_t
*shp
, int pipes
[])
2830 if(shp
->coutpipe
>=0 && shp
->cpid
)
2831 errormsg(SH_DICT
,ERROR_exit(1),e_pexists
);
2833 if(shp
->cpipe
[0]<=0 || shp
->cpipe
[1]<=0)
2835 /* first co-process */
2836 sh_pclose(shp
->cpipe
);
2837 sh_pipe(shp
->cpipe
);
2838 if((outfd
=shp
->cpipe
[1]) < 10)
2840 int fd
=fcntl(shp
->cpipe
[1],F_DUPFD
,10);
2843 shp
->fdstatus
[fd
] = (shp
->fdstatus
[outfd
]&~IOCLEX
);
2845 shp
->fdstatus
[outfd
] = IOCLOSE
;
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
;
2853 if(fcntl(shp
->cpipe
[1],F_SETFD
,FD_CLOEXEC
) >=0)
2854 shp
->fdstatus
[shp
->cpipe
[1]] |= IOCLEX
;
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
;
2867 #if SHOPT_AMP || !defined(_lib_fork)
2869 * print out function definition
2871 static void print_fun(register Namval_t
* np
, void *data
)
2873 register char *format
;
2875 if(!is_afunction(np
) || !np
->nvalue
.ip
)
2877 if(nv_isattr(np
,NV_FPOSIX
))
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);
2887 * create a shell script consisting of t->fork.forktre and execute it
2889 static int run_subshell(const Shnode_t
*t
,pid_t grp
)
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
);
2895 char *arglist
[2], *envlist
[2], devfd
[12], *cp
;
2896 Sfio_t
*sp
= sftmp(0);
2897 envlist
[0] = "_=" SH_ID
;
2899 arglist
[0] = error_info
.id
?error_info
.id
:sh
.shname
;
2900 if(*arglist
[0]=='-')
2903 strncpy(devfd
,e_devfdNN
,sizeof(devfd
));
2905 sfstack(sfstdout
,sp
);
2907 sh_offoption(SH_XTRACE
);
2908 sfwrite(sfstdout
,"typeset -A -- ",14);
2910 nv_scan(sh
.fun_tree
, print_fun
, (void*)0,0, 0);
2913 /* pass the positional parameters */
2914 char **argv
= sh
.st
.dolv
+1;
2915 sfwrite(sfstdout
,"set --",6);
2917 sfprintf(sfstdout
," %s",sh_fmtq(*argv
++));
2918 sfputc(sfstdout
,'\n');
2920 pin
= (sh
.inpipe
?sh
.inpipe
[1]:0);
2921 pout
= (sh
.outpipe
?sh
.outpipe
[0]:0);
2922 for(i
=3; i
< 10; i
++)
2924 if(sh
.fdstatus
[i
]&IOCLEX
&& i
!=pin
&& i
!=pout
)
2926 sfprintf(sfstdout
,"exec %d<&%d\n",i
,i
);
2930 sfprintf(sfstdout
,"LINENO=%d\n",t
->fork
.forkline
);
2933 sfwrite(sfstdout
,"set -x\n",7);
2934 sh_onoption(SH_XTRACE
);
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
));
2942 *cp
++ = '0' + (fd
/10);
2943 *cp
++ = '0' + fd
%10;
2946 sfsync(NIL(Sfio_t
*));
2948 sh
.shpath
= pathshell();
2949 pid
= spawnveg(sh
.shpath
,arglist
,envlist
,grp
);
2951 for(i
=3; i
< 10; i
++)
2953 if(sh
.fdstatus
[i
]&IOCLEX
&& i
!=pin
&& i
!=pout
)
2954 fcntl(i
,F_SETFD
,FD_CLOEXEC
);
2957 errormsg(SH_DICT
,ERROR_system(ERROR_NOEXEC
),e_exec
,arglist
[0]);
2960 #endif /* !_lib_fork */
2962 static void sigreset(int mode
)
2964 register char *trap
;
2965 register int sig
=sh
.st
.trapmax
;
2968 if((trap
=sh
.st
.trapcom
[sig
]) && *trap
==0)
2969 signal(sig
,mode
?sh_fault
:SIG_IGN
);
2974 * A combined fork/exec for systems with slow or non-existent fork()
2976 static pid_t
sh_ntfork(Shell_t
*shp
,const Shnode_t
*t
,char *argv
[],int *jobid
,int flag
)
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;
2985 volatile pid_t grp
= 0;
2992 # if SHOPT_AMP || !defined(_lib_fork)
2995 register Shnode_t
*tchild
= t
->fork
.forktre
;
2997 otype
= t
->tre
.tretyp
;
3001 if((tchild
->tre
.tretyp
&COMMSK
)==TCOM
)
3003 Namval_t
*np
= (Namval_t
*)(tchild
->com
.comnamp
);
3007 if(!nv_isattr(np
,BLT_ENV
))
3009 else if(strcmp(path
,"echo")==0 || memcmp(path
,"print",5)==0)
3012 else if(!tchild
->com
.comarg
)
3014 else if(tchild
->com
.comtyp
&COMSCAN
)
3016 if(tchild
->com
.comarg
->argflag
&ARG_RAW
)
3017 path
= tchild
->com
.comarg
->argval
;
3022 path
= ((struct dolnod
*)tchild
->com
.comarg
)->dolval
[ARG_SPARE
];
3023 if(!np
&& path
&& !nv_search(path
,shp
->fun_tree
,0))
3027 sh_pushcontext(&buff
,SH_JMPIO
);
3028 jmpval
= sigsetjmp(buff
.buff
,0);
3030 if((otype
&FINT
) && !sh_isstate(SH_MONITOR
))
3032 signal(SIGQUIT
,SIG_IGN
);
3033 signal(SIGINT
,SIG_IGN
);
3036 sh_iosave(shp
,0,buff
.topfd
,(char*)0);
3037 sh_iorenumber(shp
,sh_chkopen(e_devnull
),0);
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
;
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
;
3057 sh_redirect(shp
,t
->fork
.forkio
,0);
3063 signal(SIGTTIN
,SIG_DFL
);
3064 signal(SIGTTOU
,SIG_DFL
);
3066 #endif /* SIGTSTP */
3068 if(sh_isstate(SH_MONITOR
) && (job
.jobcontrol
|| (otype
&FAMP
)))
3070 if((otype
&FAMP
) || job
.curpgid
==0)
3076 spawnpid
= run_subshell(t
,grp
);
3080 sh_exec(tchild
,SH_NTFORK
);
3085 sh_popcontext(&buff
);
3086 if((otype
&FINT
) && !sh_isstate(SH_MONITOR
))
3088 signal(SIGQUIT
,sh_fault
);
3089 signal(SIGINT
,sh_fault
);
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
);
3100 signal(SIGTTIN
,SIG_IGN
);
3101 signal(SIGTTOU
,SIG_IGN
);
3103 #endif /* SIGTSTP */
3105 _sh_fork(spawnpid
,otype
,jobid
);
3106 if(grp
>0 && !(otype
&FAMP
))
3108 while(tcsetpgrp(job
.fd
,job
.curpgid
)<0 && job
.curpgid
!=spawnpid
)
3109 job
.curpgid
= spawnpid
;
3114 siglongjmp(*shp
->jmplist
,jmpval
);
3115 if(spawnpid
<0 && (otype
&FCOOP
))
3117 sh_close(shp
->coutpipe
);
3118 sh_close(shp
->cpipe
[1]);
3125 # endif /* !_lib_fork */
3126 sh_pushcontext(&buff
,SH_JMPCMD
);
3127 errorpush(&buff
.err
,ERROR_SILENT
);
3128 jmpval
= sigsetjmp(buff
.buff
,0);
3131 if((otype
&FINT
) && !sh_isstate(SH_MONITOR
))
3133 signal(SIGQUIT
,SIG_IGN
);
3134 signal(SIGINT
,SIG_IGN
);
3138 sh_redirect(shp
,t
->com
.comio
,0);
3139 error_info
.id
= *argv
;
3143 sh_scope(shp
,t
->com
.comset
,0);
3145 if(!strchr(path
=argv
[0],'/'))
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
*)))
3152 path
= stkptr(shp
->stk
,PATH_OFFSET
);
3153 stkfreeze(shp
->stk
,0);
3160 if(pp
->len
==1 && *pp
->name
=='.')
3168 else if(sh_isoption(SH_RESTRICTED
))
3169 errormsg(SH_DICT
,ERROR_exit(1),e_restricted
,path
);
3180 signal(SIGTTIN
,SIG_DFL
);
3181 signal(SIGTTOU
,SIG_DFL
);
3184 #endif /* SIGTSTP */
3186 if(sh_isstate(SH_MONITOR
) && (job
.jobcontrol
|| (otype
&FAMP
)))
3188 if((otype
&FAMP
) || job
.curpgid
==0)
3195 sfsync(NIL(Sfio_t
*));
3196 sigreset(0); /* set signals to ignore */
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
)
3204 int fd
= open(path
,O_RDONLY
);
3210 sfprintf(sh
.strbuf
,"/dev/fd/%d",fd
);
3211 if(stat(devfd
=sfstruse(sh
.strbuf
),&statb
)>=0)
3215 shp
->shpath
= pathshell();
3216 spawnpid
= path_spawn(shp
->shpath
,&argv
[-1],arge
,pp
,(grp
<<1)|1);
3222 if(spawnpid
< 0) switch(errno
=shp
->path_err
)
3225 errormsg(SH_DICT
,ERROR_system(ERROR_NOENT
),e_found
+4);
3227 errormsg(SH_DICT
,ERROR_system(ERROR_NOEXEC
),e_exec
+4);
3232 sh_popcontext(&buff
);
3234 free_list(buff
.olist
);
3238 signal(SIGTTIN
,SIG_IGN
);
3239 signal(SIGTTOU
,SIG_IGN
);
3241 #endif /* SIGTSTP */
3243 sigreset(1); /* restore ignored signals */
3247 if(jmpval
==SH_JMPSCRIPT
)
3248 nv_setlist(t
->com
.comset
,NV_EXPORT
|NV_IDENT
|NV_ASSIGN
,0);
3251 sh_iorestore(shp
,buff
.topfd
,jmpval
);
3252 if(jmpval
>SH_JMPCMD
)
3253 siglongjmp(*shp
->jmplist
,jmpval
);
3256 _sh_fork(spawnpid
,otype
,jobid
);
3259 job
.curpgid
= spawnpid
;
3261 if(grp
>0 && !(otype
&FAMP
))
3263 while(tcsetpgrp(job
.fd
,job
.curpgid
)<0 && job
.curpgid
!=spawnpid
)
3264 job
.curpgid
= spawnpid
;
3266 # endif /* SIGTSTP */
3275 # ifdef _was_lib_fork
3276 # define _lib_fork 1
3281 errormsg(SH_DICT
,ERROR_exit(3),e_notimp
,"fork");
3284 # endif /* _lib_fork */
3285 #endif /* SHOPT_SPAWN */