diff options
author | Andy Fiddaman <omnios@citrus-it.co.uk> | 2020-12-27 17:47:37 +0000 |
---|---|---|
committer | Andy Fiddaman <omnios@citrus-it.co.uk> | 2021-01-30 17:13:33 +0000 |
commit | b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f (patch) | |
tree | 6a37e590faffb9bb9af66887de645c546445036c /usr/src/lib/libshell/common/sh/xec.c | |
parent | df36e06d12cbf655ddf22339ef8c39fa2b83ebf8 (diff) | |
download | illumos-gate-b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f.tar.gz |
13405 ksh93 update to 2012-08-01
13434 sh: mishandles backslash as last character of a block of input
11750 ksh mkdir builtin doesn't honor special file permissions
9199 ksh93 builtin *grep -v mishandles blank lines, blows up libgcrypt-config
6756 sh (and ksh) have issues with ${1+"$@"}
6520 ksh: sleep could wait forever
4860 ksh93: core in printf
3791 /bin/sh's builtin 'rm' busted: 'rm -f' without arguments returns error
1047 ksh overwrites child core files
880 ksh93 coredumps on 'unset'
499 "interrupted system call" when using "tee" builtin in ksh
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
Reviewed by: Dominik Hassler <hadfl@omnios.org>
Approved by: Rich Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/lib/libshell/common/sh/xec.c')
-rw-r--r-- | usr/src/lib/libshell/common/sh/xec.c | 3288 |
1 files changed, 0 insertions, 3288 deletions
diff --git a/usr/src/lib/libshell/common/sh/xec.c b/usr/src/lib/libshell/common/sh/xec.c deleted file mode 100644 index 3975060421..0000000000 --- a/usr/src/lib/libshell/common/sh/xec.c +++ /dev/null @@ -1,3288 +0,0 @@ -/*********************************************************************** -* * -* This software is part of the ast package * -* Copyright (c) 1982-2010 AT&T Intellectual Property * -* and is licensed under the * -* Common Public License, Version 1.0 * -* by AT&T Intellectual Property * -* * -* A copy of the License is available at * -* http://www.opensource.org/licenses/cpl1.0.txt * -* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * -* * -* Information and Software Systems Research * -* AT&T Research * -* Florham Park NJ * -* * -* David Korn <dgk@research.att.com> * -* * -***********************************************************************/ -#pragma prototyped -/* - * UNIX shell parse tree executer - * - * David Korn - * AT&T Labs - * - */ - -#include "defs.h" -#include <fcin.h> -#include "variables.h" -#include "path.h" -#include "name.h" -#include "io.h" -#include "shnodes.h" -#include "jobs.h" -#include "test.h" -#include "builtins.h" -#include "FEATURE/time" -#include "FEATURE/externs" -#include "FEATURE/locale" -#include "streval.h" - -#if !_std_malloc -# include <vmalloc.h> -#endif - -#if _lib_vfork -# include <ast_vfork.h> -#else -# define vfork() fork() -#endif - -#define SH_NTFORK SH_TIMING - -#if _lib_nice - extern int nice(int); -#endif /* _lib_nice */ -#if !_lib_spawnveg -# define spawnveg(a,b,c,d) spawnve(a,b,c) -#endif /* !_lib_spawnveg */ -#if SHOPT_SPAWN - static pid_t sh_ntfork(Shell_t*,const Shnode_t*,char*[],int*,int); -#endif /* SHOPT_SPAWN */ - -static void sh_funct(Shell_t *,Namval_t*, int, char*[], struct argnod*,int); -static int trim_eq(const char*, const char*); -static void coproc_init(Shell_t*, int pipes[]); - -static void *timeout; -static char pipejob; - -struct funenv -{ - Namval_t *node; - struct argnod *env; -}; - -/* ======== command execution ========*/ - -/* - * print time <t> in h:m:s format with precision <p> - */ -static void l_time(Sfio_t *outfile,register clock_t t,int p) -{ - register int min, sec, frac; - register int hr; - if(p) - { - frac = t%sh.lim.clk_tck; - frac = (frac*100)/sh.lim.clk_tck; - } - t /= sh.lim.clk_tck; - sec = t%60; - t /= 60; - min = t%60; - if(hr=t/60) - sfprintf(outfile,"%dh",hr); - if(p) - sfprintf(outfile,"%dm%d%c%0*ds",min,sec,GETDECIMAL(0),p,frac); - else - sfprintf(outfile,"%dm%ds",min,sec); -} - -static int p_time(Shell_t *shp, Sfio_t *out, const char *format, clock_t *tm) -{ - int c,p,l,n,offset = staktell(); - const char *first; - double d; - Stk_t *stkp = shp->stk; - for(first=format ; c= *format; format++) - { - if(c!='%') - continue; - sfwrite(stkp, first, format-first); - n = l = 0; - p = 3; - if((c= *++format) == '%') - { - first = format; - continue; - } - if(c>='0' && c <='9') - { - p = (c>'3')?3:(c-'0'); - c = *++format; - } - else if(c=='P') - { - if(d=tm[0]) - d = 100.*(((double)(tm[1]+tm[2]))/d); - p = 2; - goto skip; - } - if(c=='l') - { - l = 1; - c = *++format; - } - if(c=='U') - n = 1; - else if(c=='S') - n = 2; - else if(c!='R') - { - stkseek(stkp,offset); - errormsg(SH_DICT,ERROR_exit(0),e_badtformat,c); - return(0); - } - d = (double)tm[n]/sh.lim.clk_tck; - skip: - if(l) - l_time(stkp, tm[n], p); - else - sfprintf(stkp,"%.*f",p, d); - first = format+1; - } - if(format>first) - sfwrite(stkp,first, format-first); - sfputc(stkp,'\n'); - n = stktell(stkp)-offset; - sfwrite(out,stkptr(stkp,offset),n); - stkseek(stkp,offset); - return(n); -} - -#if SHOPT_OPTIMIZE -/* - * clear argument pointers that point into the stack - */ -static int p_arg(struct argnod*,int); -static int p_switch(struct regnod*); -static int p_comarg(register struct comnod *com) -{ - Namval_t *np=com->comnamp; - int n = p_arg(com->comset,ARG_ASSIGN); - if(com->comarg && (com->comtyp&COMSCAN)) - n+= p_arg(com->comarg,0); - if(com->comstate && np) - { - /* call builtin to cleanup state */ - Shbltin_t *bp = &sh.bltindata; - void *save_ptr = bp->ptr; - void *save_data = bp->data; - bp->bnode = np; - bp->vnode = com->comnamq; - bp->ptr = nv_context(np); - bp->data = com->comstate; - bp->flags = SH_END_OPTIM; - (*funptr(np))(0,(char**)0, bp); - bp->ptr = save_ptr; - bp->data = save_data; - } - com->comstate = 0; - if(com->comarg && !np) - n++; - return(n); -} - -extern void sh_optclear(Shell_t*, void*); - -static int sh_tclear(register Shnode_t *t) -{ - int n=0; - if(!t) - return(0); - switch(t->tre.tretyp&COMMSK) - { - case TTIME: - case TPAR: - return(sh_tclear(t->par.partre)); - case TCOM: - return(p_comarg((struct comnod*)t)); - case TSETIO: - case TFORK: - return(sh_tclear(t->fork.forktre)); - case TIF: - n=sh_tclear(t->if_.iftre); - n+=sh_tclear(t->if_.thtre); - n+=sh_tclear(t->if_.eltre); - return(n); - case TWH: - if(t->wh.whinc) - n=sh_tclear((Shnode_t*)(t->wh.whinc)); - n+=sh_tclear(t->wh.whtre); - n+=sh_tclear(t->wh.dotre); - return(n); - case TLST: - case TAND: - case TORF: - case TFIL: - n=sh_tclear(t->lst.lstlef); - return(n+sh_tclear(t->lst.lstrit)); - case TARITH: - return(p_arg(t->ar.arexpr,ARG_ARITH)); - case TFOR: - n=sh_tclear(t->for_.fortre); - return(n+sh_tclear((Shnode_t*)t->for_.forlst)); - case TSW: - n=p_arg(t->sw.swarg,0); - return(n+p_switch(t->sw.swlst)); - case TFUN: - n=sh_tclear(t->funct.functtre); - return(n+sh_tclear((Shnode_t*)t->funct.functargs)); - case TTST: - if((t->tre.tretyp&TPAREN)==TPAREN) - return(sh_tclear(t->lst.lstlef)); - else - { - n=p_arg(&(t->lst.lstlef->arg),0); - if(t->tre.tretyp&TBINARY) - n+=p_arg(&(t->lst.lstrit->arg),0); - } - } - return(n); -} - -static int p_arg(register struct argnod *arg,int flag) -{ - while(arg) - { - if(strlen(arg->argval) || (arg->argflag==ARG_RAW)) - arg->argchn.ap = 0; - else if(flag==0) - sh_tclear((Shnode_t*)arg->argchn.ap); - else - sh_tclear(((struct fornod*)arg->argchn.ap)->fortre); - arg = arg->argnxt.ap; - } - return(0); -} - -static int p_switch(register struct regnod *reg) -{ - int n=0; - while(reg) - { - n+=p_arg(reg->regptr,0); - n+=sh_tclear(reg->regcom); - reg = reg->regnxt; - } - return(n); -} -# define OPTIMIZE_FLAG (ARG_OPTIMIZE) -# define OPTIMIZE (flags&OPTIMIZE_FLAG) -#else -# define OPTIMIZE_FLAG (0) -# define OPTIMIZE (0) -# define sh_tclear(x) -#endif /* SHOPT_OPTIMIZE */ - -static void out_pattern(Sfio_t *iop, register const char *cp, int n) -{ - register int c; - do - { - switch(c= *cp) - { - case 0: - if(n<0) - return; - c = n; - break; - case '\n': - sfputr(iop,"$'\\n",'\''); - continue; - case '\\': - if (!(c = *++cp)) - c = '\\'; - /*FALLTHROUGH*/ - case ' ': - case '<': case '>': case ';': - case '$': case '`': case '\t': - sfputc(iop,'\\'); - break; - } - sfputc(iop,c); - } - while(*cp++); -} - -static void out_string(Sfio_t *iop, register const char *cp, int c, int quoted) -{ - if(quoted) - { - int n = stktell(stkstd); - cp = sh_fmtq(cp); - if(iop==stkstd && cp==stkptr(stkstd,n)) - { - *stkptr(stkstd,stktell(stkstd)-1) = c; - return; - } - } - sfputr(iop,cp,c); -} - -struct Level -{ - Namfun_t hdr; - short maxlevel; -}; - -/* - * this is for a debugger but it hasn't been tested yet - * if a debug script sets .sh.level it should set up the scope - * as if you were executing in that level - */ -static void put_level(Namval_t* np,const char *val,int flags,Namfun_t *fp) -{ - Shscope_t *sp; - struct Level *lp = (struct Level*)fp; - int16_t level, oldlevel = (int16_t)nv_getnum(np); - nv_putv(np,val,flags,fp); - if(!val) - { - fp = nv_stack(np, NIL(Namfun_t*)); - if(fp && !fp->nofree) - free((void*)fp); - return; - } - level = nv_getnum(np); - if(level<0 || level > lp->maxlevel) - { - nv_putv(np, (char*)&oldlevel, NV_INT16, fp); - /* perhaps this should be an error */ - return; - } - if(level==oldlevel) - return; - if(sp = sh_getscope(level,SEEK_SET)) - { - sh_setscope(sp); - error_info.id = sp->cmdname; - - } -} - -static const Namdisc_t level_disc = { sizeof(struct Level), put_level }; - -static struct Level *init_level(int level) -{ - struct Level *lp = newof(NiL,struct Level,1,0); - lp->maxlevel = level; - _nv_unset(SH_LEVELNOD,0); - nv_onattr(SH_LEVELNOD,NV_INT16|NV_NOFREE); - nv_putval(SH_LEVELNOD,(char*)&lp->maxlevel,NV_INT16); - lp->hdr.disc = &level_disc; - nv_disc(SH_LEVELNOD,&lp->hdr,NV_FIRST); - return(lp); -} - -/* - * write the current common on the stack and make it available as .sh.command - */ -int sh_debug(Shell_t *shp, const char *trap, const char *name, const char *subscript, char *const argv[], int flags) -{ - Stk_t *stkp=shp->stk; - struct sh_scoped savst; - Namval_t *np = SH_COMMANDNOD; - char *sav = stkptr(stkp,0); - int n=4, offset=stktell(stkp); - const char *cp = "+=( "; - Sfio_t *iop = stkstd; - short level; - if(shp->indebug) - return(0); - shp->indebug = 1; - if(name) - { - sfputr(iop,name,-1); - if(subscript) - { - sfputc(iop,'['); - out_string(iop,subscript,']',1); - } - if(!(flags&ARG_APPEND)) - cp+=1, n-=1; - if(!(flags&ARG_ASSIGN)) - n -= 2; - sfwrite(iop,cp,n); - } - if(*argv && !(flags&ARG_RAW)) - out_string(iop, *argv++,' ', 0); - n = (flags&ARG_ARITH); - while(cp = *argv++) - { - if((flags&ARG_EXP) && argv[1]==0) - out_pattern(iop, cp,' '); - else - out_string(iop, cp,' ',n?0: (flags&(ARG_RAW|ARG_NOGLOB))||*argv); - } - if(flags&ARG_ASSIGN) - sfputc(iop,')'); - else if(iop==stkstd) - *stkptr(stkp,stktell(stkp)-1) = 0; - np->nvalue.cp = stkfreeze(stkp,1); - /* now setup .sh.level variable */ - shp->st.lineno = error_info.line; - level = shp->fn_depth+shp->dot_depth; - if(!SH_LEVELNOD->nvfun || !SH_LEVELNOD->nvfun->disc || nv_isattr(SH_LEVELNOD,NV_INT16|NV_NOFREE)!=(NV_INT16|NV_NOFREE)) - init_level(level); - else - nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16); - savst = shp->st; - shp->st.trap[SH_DEBUGTRAP] = 0; - n = sh_trap(trap,0); - np->nvalue.cp = 0; - shp->indebug = 0; - if(shp->st.cmdname) - error_info.id = shp->st.cmdname; - nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); - nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); - shp->st = savst; - if(sav != stkptr(stkp,0)) - stkset(stkp,sav,0); - else - stkseek(stkp,offset); - return(n); -} - -/* - * Given stream <iop> compile and execute - */ -int sh_eval(register Sfio_t *iop, int mode) -{ - register Shnode_t *t; - Shell_t *shp = sh_getinterp(); - struct slnod *saveslp = shp->st.staklist; - int jmpval; - struct checkpt *pp = (struct checkpt*)shp->jmplist; - struct checkpt buff; - static Sfio_t *io_save; - volatile int traceon=0, lineno=0; - int binscript=shp->binscript; - io_save = iop; /* preserve correct value across longjmp */ - shp->binscript = 0; -#define SH_TOPFUN 0x8000 /* this is a temporary tksh hack */ - if (mode & SH_TOPFUN) - { - mode ^= SH_TOPFUN; - shp->fn_reset = 1; - } - sh_pushcontext(&buff,SH_JMPEVAL); - buff.olist = pp->olist; - jmpval = sigsetjmp(buff.buff,0); - while(jmpval==0) - { - if(mode&SH_READEVAL) - { - lineno = shp->inlineno; - if(traceon=sh_isoption(SH_XTRACE)) - sh_offoption(SH_XTRACE); - } - t = (Shnode_t*)sh_parse(shp,iop,(mode&(SH_READEVAL|SH_FUNEVAL))?mode&SH_FUNEVAL:SH_NL); - if(!(mode&SH_FUNEVAL) || !sfreserve(iop,0,0)) - { - if(!(mode&SH_READEVAL)) - sfclose(iop); - io_save = 0; - mode &= ~SH_FUNEVAL; - } - mode &= ~SH_READEVAL; - if(!sh_isoption(SH_VERBOSE)) - sh_offstate(SH_VERBOSE); - if((mode&~SH_FUNEVAL) && shp->hist_ptr) - { - hist_flush(shp->hist_ptr); - mode = sh_state(SH_INTERACTIVE); - } - sh_exec(t,sh_isstate(SH_ERREXIT)|sh_isstate(SH_NOFORK)|(mode&~SH_FUNEVAL)); - if(!(mode&SH_FUNEVAL)) - break; - } - sh_popcontext(&buff); - shp->binscript = binscript; - if(traceon) - sh_onoption(SH_XTRACE); - if(lineno) - shp->inlineno = lineno; - if(io_save) - sfclose(io_save); - sh_freeup(shp); - shp->st.staklist = saveslp; - shp->fn_reset = 0; - if(jmpval>SH_JMPEVAL) - siglongjmp(*shp->jmplist,jmpval); - return(shp->exitval); -} - -#if SHOPT_FASTPIPE -static int pipe_exec(Shell_t* shp,int pv[], Shnode_t *t, int errorflg) -{ - struct checkpt buff; - register Shnode_t *tchild = t->fork.forktre; - Namval_t *np; - int jmpval; - volatile Sfio_t *iop; - volatile int r; - if((tchild->tre.tretyp&COMMSK)!=TCOM || !(np=(Namval_t*)(tchild->com.comnamp))) - { - sh_pipe(pv); - return(sh_exec(t,errorflg)); - } - pv[0] = shp->lim.open_max; - shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK; - pv[1] = shp->lim.open_max+1; - shp->fdstatus[pv[1]] = IOWRITE|IOSEEK; - iop = sftmp(IOBSIZE+1); - shp->sftable[shp->lim.open_max+1] = iop; - sh_pushcontext(&buff,SH_JMPIO); - if(t->tre.tretyp&FPIN) - sh_iosave(shp,0,shp->topfd,(char*)0); - sh_iosave(shp,1,shp->topfd,(char*)0); - jmpval = sigsetjmp(buff.buff,0); - if(jmpval==0) - { - if(t->tre.tretyp&FPIN) - sh_iorenumber(shp,shp->inpipe[0],0); - sh_iorenumber(shp,shp->lim.open_max+1,1); - r = sh_exec(tchild,errorflg); - if(sffileno(sfstdout)>=0) - pv[0] = sfsetfd(sfstdout,10); - iop = sfswap(sfstdout,0); - } - sh_popcontext(&buff); - shp->sftable[pv[0]] = iop; - shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK; - sfset(iop,SF_WRITE,0); - sfseek(iop,0L,SEEK_SET); - sh_iorestore(shp,buff.topfd,jmpval); - if(jmpval>SH_JMPIO) - siglongjmp(*shp->jmplist,jmpval); - return(r); -} -#endif /* SHOPT_FASTPIPE */ - -/* - * returns 1 when option -<c> is specified - */ -static int checkopt(char *argv[], int c) -{ - char *cp; - while(cp = *++argv) - { - if(*cp=='+') - continue; - if(*cp!='-' || cp[1]=='-') - break; - if(strchr(++cp,c)) - return(1); - if(*cp=='h' && cp[1]==0 && *++argv==0) - break; - } - return(0); -} - -static void free_list(struct openlist *olist) -{ - struct openlist *item,*next; - for(item=olist;item;item=next) - { - next = item->next; - free((void*)item); - } -} - -/* - * set ${.sh.name} and ${.sh.subscript} - * set _ to reference for ${.sh.name}[$.sh.subscript] - */ -static int set_instance(Shell_t *shp,Namval_t *nq, Namval_t *node, struct Namref *nr) -{ - char *sp=0,*cp = nv_name(nq); - Namarr_t *ap; - memset(nr,0,sizeof(*nr)); - nr->np = nq; - nr->root = sh.var_tree; - nr->table = sh.last_table; - shp->instance = 1; - if((ap=nv_arrayptr(nq)) && (sp = nv_getsub(nq))) - sp = strdup(sp); - shp->instance = 0; - if(sh.var_tree!=sh.var_base && !nv_open(cp,nr->root,NV_VARNAME|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)) - nr->root = sh.var_base; - nv_putval(SH_NAMENOD, cp, NV_NOFREE); - memcpy(node,L_ARGNOD,sizeof(*node)); - L_ARGNOD->nvalue.nrp = nr; - L_ARGNOD->nvflag = NV_REF|NV_NOFREE; - L_ARGNOD->nvfun = 0; - L_ARGNOD->nvenv = 0; - if(sp) - { - nv_putval(SH_SUBSCRNOD,nr->sub=sp,NV_NOFREE); - return(ap->nelem&ARRAY_SCAN); - } - return(0); -} - -static void unset_instance(Namval_t *nq, Namval_t *node, struct Namref *nr,long mode) -{ - L_ARGNOD->nvalue.nrp = node->nvalue.nrp; - L_ARGNOD->nvflag = node->nvflag; - L_ARGNOD->nvfun = node->nvfun; - if(nr->sub) - { - nv_putsub(nq, nr->sub, mode); - free((void*)nr->sub); - } - nv_unset(SH_NAMENOD); - nv_unset(SH_SUBSCRNOD); -} - -int sh_exec(register const Shnode_t *t, int flags) -{ - register Shell_t *shp = &sh; - Stk_t *stkp = shp->stk; - sh_sigcheck(); - if(t && !shp->st.execbrk && !sh_isoption(SH_NOEXEC)) - { - register int type = flags; - register char *com0 = 0; - int errorflg = (type&sh_state(SH_ERREXIT))|OPTIMIZE; - int execflg = (type&sh_state(SH_NOFORK)); - int execflg2 = (type&sh_state(SH_FORKED)); - int mainloop = (type&sh_state(SH_INTERACTIVE)); -#if SHOPT_AMP || SHOPT_SPAWN - int ntflag = (type&sh_state(SH_NTFORK)); -#else - int ntflag = 0; -#endif - int topfd = shp->topfd; - char *sav=stkptr(stkp,0); - char *cp=0, **com=0, *comn; - int argn; - int skipexitset = 0; - int was_interactive = 0; - int was_errexit = sh_isstate(SH_ERREXIT); - int was_monitor = sh_isstate(SH_MONITOR); - int echeck = 0; - if(flags&sh_state(SH_INTERACTIVE)) - { - if(pipejob==2) - job_unlock(); - pipejob = 0; - job.curpgid = 0; - flags &= ~sh_state(SH_INTERACTIVE); - } - sh_offstate(SH_ERREXIT); - sh_offstate(SH_DEFPATH); - if(was_errexit&flags) - sh_onstate(SH_ERREXIT); - if(was_monitor&flags) - sh_onstate(SH_MONITOR); - type = t->tre.tretyp; - if(!shp->intrap) - shp->oldexit=shp->exitval; - shp->exitval=0; - shp->lastsig = 0; - shp->lastpath = 0; - switch(type&COMMSK) - { - case TCOM: - { - register struct argnod *argp; - char *trap; - Namval_t *np, *nq, *last_table; - struct ionod *io; - int command=0, flgs=NV_ASSIGN; - shp->bltindata.invariant = type>>(COMBITS+2); - type &= (COMMSK|COMSCAN); - sh_stats(STAT_SCMDS); - error_info.line = t->com.comline-shp->st.firstline; - com = sh_argbuild(shp,&argn,&(t->com),OPTIMIZE); - echeck = 1; - if(t->tre.tretyp&COMSCAN) - { - argp = t->com.comarg; - if(argp && *com && !(argp->argflag&ARG_RAW)) - sh_sigcheck(); - } - np = (Namval_t*)(t->com.comnamp); - nq = (Namval_t*)(t->com.comnamq); - com0 = com[0]; - shp->xargexit = 0; - while(np==SYSCOMMAND) - { - register int n = b_command(0,com,&shp->bltindata); - if(n==0) - break; - command += n; - np = 0; - if(!(com0= *(com+=n))) - break; - np = nv_bfsearch(com0, shp->bltin_tree, &nq, &cp); - } - if(shp->xargexit) - { - shp->xargmin -= command; - shp->xargmax -= command; - } - else - shp->xargmin = 0; - argn -= command; - if(!command && np && is_abuiltin(np)) - np = dtsearch(shp->fun_tree,np); - if(com0) - { - if(!np && !strchr(com0,'/')) - { - Dt_t *root = command?shp->bltin_tree:shp->fun_tree; - np = nv_bfsearch(com0, root, &nq, &cp); -#if SHOPT_NAMESPACE - if(shp->namespace && !nq && !cp) - { - int offset = stktell(stkp); - sfputr(stkp,nv_name(shp->namespace),-1); - sfputc(stkp,'.'); - sfputr(stkp,com0,0); - stkseek(stkp,offset); - np = nv_bfsearch(stkptr(stkp,offset), root, &nq, &cp); - } -#endif /* SHOPT_NAMESPACE */ - } - comn = com[argn-1]; - } - io = t->tre.treio; - if(shp->envlist = argp = t->com.comset) - { - if(argn==0 || (np && nv_isattr(np,BLT_SPC))) - { - Namval_t *tp=0; - if(argn) - { - if(checkopt(com,'A')) - flgs |= NV_ARRAY; - else if(checkopt(com,'a')) - flgs |= NV_IARRAY; - } -#if SHOPT_BASH - if(np==SYSLOCAL) - { - if(!nv_getval(SH_FUNNAMENOD)) - errormsg(SH_DICT,ERROR_exit(1),"%s: can only be used in a function",com0); - if(!shp->st.var_local) - { - sh_scope(shp,(struct argnod*)0,0); - shp->st.var_local = shp->var_tree; - } - - } - if(np==SYSTYPESET || np==SYSLOCAL) -#else - if(np==SYSTYPESET || (np && np->nvalue.bfp==SYSTYPESET->nvalue.bfp)) -#endif - { - if(np!=SYSTYPESET) - { - shp->typeinit = np; - tp = nv_type(np); - } - if(checkopt(com,'C')) - flgs |= NV_COMVAR; - if(checkopt(com,'S')) - flgs |= NV_STATIC; - if(checkopt(com,'n')) - flgs |= NV_NOREF; - else if(!shp->typeinit && (checkopt(com,'L') || checkopt(com,'R') || checkopt(com,'Z'))) - flgs |= NV_UNJUST; -#if SHOPT_TYPEDEF - else if(argn>=3 && checkopt(com,'T')) - { - shp->prefix = NV_CLASS; - flgs |= NV_TYPE; - - } -#endif /* SHOPT_TYPEDEF */ - if((shp->fn_depth && !shp->prefix) || np==SYSLOCAL) - flgs |= NV_NOSCOPE; - } - else if(np==SYSEXPORT) - flgs |= NV_EXPORT; - if(flgs&(NV_EXPORT|NV_NOREF)) - flgs |= NV_IDENT; - else - flgs |= NV_VARNAME; -#if 0 - if(OPTIMIZE) - flgs |= NV_TAGGED; -#endif - nv_setlist(argp,flgs,tp); - if(np==shp->typeinit) - shp->typeinit = 0; - shp->envlist = argp; - argp = NULL; - } - } - last_table = shp->last_table; - shp->last_table = 0; - if((io||argn)) - { - Shbltin_t *bp=0; - static char *argv[1]; - int tflags = 1; - if(np && nv_isattr(np,BLT_DCL)) - tflags |= 2; - if(argn==0) - { - /* fake 'true' built-in */ - np = SYSTRUE; - *argv = nv_name(np); - com = argv; - } - /* set +x doesn't echo */ - else if((np!=SYSSET) && sh_isoption(SH_XTRACE)) - sh_trace(com-command,tflags); - else if((t->tre.tretyp&FSHOWME) && sh_isoption(SH_SHOWME)) - { - int ison = sh_isoption(SH_XTRACE); - if(!ison) - sh_onoption(SH_XTRACE); - sh_trace(com-command,tflags); - if(io) - sh_redirect(shp,io,SH_SHOWME); - if(!ison) - sh_offoption(SH_XTRACE); - break; - } - if(trap=shp->st.trap[SH_DEBUGTRAP]) - { - int n = sh_debug(shp,trap,(char*)0,(char*)0, com, ARG_RAW); - if(n==255 && shp->fn_depth+shp->dot_depth) - { - np = SYSRETURN; - argn = 1; - com[0] = np->nvname; - com[1] = 0; - io = 0; - argp = 0; - } - else if(n==2) - break; - } - if(io) - sfsync(shp->outpool); - shp->lastpath = 0; - if(!np && !strchr(com0,'/')) - { - if(path_search(com0,NIL(Pathcomp_t**),1)) - { - error_info.line = t->com.comline-shp->st.firstline; - if((np=nv_search(com0,shp->fun_tree,0)) && !np->nvalue.ip) - { - Namval_t *mp=nv_search(com0,shp->bltin_tree,0); - if(mp) - np = mp; - } - } - else - { - if((np=nv_search(com0,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp) - np=nv_search(nv_getval(np),shp->bltin_tree,0); - else - np = 0; - } - } - if(np && pipejob==2) - { - job_unlock(); - pipejob = 1; - } - /* check for builtins */ - if(np && is_abuiltin(np)) - { - volatile int scope=0, share=0; - volatile void *save_ptr; - volatile void *save_data; - int jmpval, save_prompt; - int was_nofork = execflg?sh_isstate(SH_NOFORK):0; - struct checkpt buff; - unsigned long was_vi=0, was_emacs=0, was_gmacs=0; - struct stat statb; - bp = &shp->bltindata; - save_ptr = bp->ptr; - save_data = bp->data; - memset(&statb, 0, sizeof(struct stat)); - if(strchr(nv_name(np),'/')) - { - /* - * disable editors for built-in - * versions of commands on PATH - */ - was_vi = sh_isoption(SH_VI); - was_emacs = sh_isoption(SH_EMACS); - was_gmacs = sh_isoption(SH_GMACS); - sh_offoption(SH_VI); - sh_offoption(SH_EMACS); - sh_offoption(SH_GMACS); - } - if(execflg) - sh_onstate(SH_NOFORK); - sh_pushcontext(&buff,SH_JMPCMD); - jmpval = sigsetjmp(buff.buff,1); - if(jmpval == 0) - { - if(!(nv_isattr(np,BLT_ENV))) - error_info.flags |= ERROR_SILENT; - errorpush(&buff.err,0); - if(io) - { - struct openlist *item; - if(np==SYSLOGIN) - type=1; - else if(np==SYSEXEC) - type=1+!com[1]; - else - type = (execflg && !shp->subshell && !shp->st.trapcom[0]); - sh_redirect(shp,io,type); - for(item=buff.olist;item;item=item->next) - item->strm=0; - } - if(!(nv_isattr(np,BLT_ENV))) - { - if(bp->nosfio) - { - if(!shp->pwd) - path_pwd(0); - if(shp->pwd) - stat(".",&statb); - } - sfsync(NULL); - share = sfset(sfstdin,SF_SHARE,0); - sh_onstate(SH_STOPOK); - sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE); - sfset(sfstderr,SF_LINE,1); - save_prompt = shp->nextprompt; - shp->nextprompt = 0; - } - if(argp) - { - scope++; - sh_scope(shp,argp,0); - } - opt_info.index = opt_info.offset = 0; - opt_info.disc = 0; - error_info.id = *com; - if(argn) - shp->exitval = 0; - shp->bltinfun = funptr(np); - bp->bnode = np; - bp->vnode = nq; - bp->ptr = nv_context(np); - bp->data = t->com.comstate; - bp->sigset = 0; - bp->notify = 0; - bp->flags = (OPTIMIZE!=0); - if(shp->subshell && nv_isattr(np,BLT_NOSFIO)) - sh_subtmpfile(0); - if(execflg && !shp->subshell && - !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && shp->fn_depth==0 && !nv_isattr(np,BLT_ENV)) - { - /* do close-on-exec */ - int fd; - for(fd=0; fd < shp->lim.open_max; fd++) - if((shp->fdstatus[fd]&IOCLEX)&&fd!=shp->infd) - sh_close(fd); - } - if(argn) - shp->exitval = (*shp->bltinfun)(argn,com,(void*)bp); - if(error_info.flags&ERROR_INTERACTIVE) - tty_check(ERRIO); - ((Shnode_t*)t)->com.comstate = shp->bltindata.data; - bp->data = (void*)save_data; - if(!nv_isattr(np,BLT_EXIT) && shp->exitval!=SH_RUNPROG) - shp->exitval &= SH_EXITMASK; - } - else - { - struct openlist *item; - for(item=buff.olist;item;item=item->next) - { - if(item->strm) - { - sfclrlock(item->strm); - if(shp->hist_ptr && item->strm == shp->hist_ptr->histfp) - hist_close(shp->hist_ptr); - else - sfclose(item->strm); - } - } - if(shp->bltinfun && (error_info.flags&ERROR_NOTIFY)) - (*shp->bltinfun)(-2,com,(void*)bp); - /* failure on special built-ins fatal */ - if(jmpval<=SH_JMPCMD && (!nv_isattr(np,BLT_SPC) || command)) - jmpval=0; - } - if(bp && bp->ptr!= nv_context(np)) - np->nvfun = (Namfun_t*)bp->ptr; - if(execflg && !was_nofork) - sh_offstate(SH_NOFORK); - if(!(nv_isattr(np,BLT_ENV))) - { - if(bp->nosfio && shp->pwd) - { - struct stat stata; - stat(".",&stata); - /* restore directory changed */ - if(statb.st_ino!=stata.st_ino || statb.st_dev!=stata.st_dev) - chdir(shp->pwd); - } - sh_offstate(SH_STOPOK); - if(share&SF_SHARE) - sfset(sfstdin,SF_PUBLIC|SF_SHARE,1); - sfset(sfstderr,SF_LINE,0); - sfpool(sfstderr,shp->outpool,SF_WRITE); - sfpool(sfstdin,NIL(Sfio_t*),SF_WRITE); - shp->nextprompt = save_prompt; - } - sh_popcontext(&buff); - errorpop(&buff.err); - error_info.flags &= ~(ERROR_SILENT|ERROR_NOTIFY); - shp->bltinfun = 0; - if(buff.olist) - free_list(buff.olist); - if(was_vi) - sh_onoption(SH_VI); - else if(was_emacs) - sh_onoption(SH_EMACS); - else if(was_gmacs) - sh_onoption(SH_GMACS); - if(scope) - sh_unscope(shp); - bp->ptr = (void*)save_ptr; - bp->data = (void*)save_data; - /* don't restore for subshell exec */ - if((shp->topfd>topfd) && !(shp->subshell && np==SYSEXEC)) - sh_iorestore(shp,topfd,jmpval); - if(jmpval) - siglongjmp(*shp->jmplist,jmpval); -#if 0 - if(flgs&NV_STATIC) - ((Shnode_t*)t)->com.comset = 0; -#endif - if(shp->exitval >=0) - goto setexit; - np = 0; - type=0; - } - /* check for functions */ - if(!command && np && nv_isattr(np,NV_FUNCTION)) - { - volatile int indx; - int jmpval=0; - struct checkpt buff; - Namval_t node; - struct Namref nr; - long mode; - register struct slnod *slp; - if(!np->nvalue.ip) - { - indx = path_search(com0,NIL(Pathcomp_t**),0); - if(indx==1) - np = nv_search(com0,shp->fun_tree,HASH_NOSCOPE); - - if(!np->nvalue.ip) - { - if(indx==1) - { - errormsg(SH_DICT,ERROR_exit(0),e_defined,com0); - shp->exitval = ERROR_NOEXEC; - } - else - { - errormsg(SH_DICT,ERROR_exit(0),e_found,"function"); - shp->exitval = ERROR_NOENT; - } - goto setexit; - } - } - /* increase refcnt for unset */ - slp = (struct slnod*)np->nvenv; - sh_funstaks(slp->slchild,1); - staklink(slp->slptr); - if(nq) - { - shp->last_table = last_table; - mode = set_instance(shp,nq,&node,&nr); - } - if(io) - { - indx = shp->topfd; - sh_pushcontext(&buff,SH_JMPCMD); - jmpval = sigsetjmp(buff.buff,0); - } - if(jmpval == 0) - { - if(io) - indx = sh_redirect(shp,io,execflg); - sh_funct(shp,np,argn,com,t->com.comset,(flags&~OPTIMIZE_FLAG)); - } - if(io) - { - if(buff.olist) - free_list(buff.olist); - sh_popcontext(&buff); - sh_iorestore(shp,indx,jmpval); - } - if(nq) - unset_instance(nq,&node,&nr,mode); - sh_funstaks(slp->slchild,-1); - stakdelete(slp->slptr); - if(jmpval > SH_JMPFUN) - siglongjmp(*shp->jmplist,jmpval); - goto setexit; - } - } - else if(!io) - { - setexit: - exitset(); - break; - } - } - /* FALLTHROUGH */ - case TFORK: - { - register pid_t parent; - int no_fork,jobid; - int pipes[2]; - if(shp->subshell) - { - if(shp->subshare) - sh_subtmpfile(1); - else - sh_subfork(); - } - no_fork = !ntflag && !(type&(FAMP|FPOU)) && - !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && - ((struct checkpt*)shp->jmplist)->mode!=SH_JMPEVAL && - (execflg2 || (execflg && - !shp->subshell && shp->fn_depth==0 && - !(pipejob && sh_isoption(SH_PIPEFAIL)) - )); - if(sh_isstate(SH_PROFILE) || shp->dot_depth) - { - /* disable foreground job monitor */ - if(!(type&FAMP)) - sh_offstate(SH_MONITOR); -#if SHOPT_DEVFD - else if(!(type&FINT)) - sh_offstate(SH_MONITOR); -#endif /* SHOPT_DEVFD */ - } - if(no_fork) - job.parent=parent=0; - else - { -#ifdef SHOPT_BGX - int maxjob; - if(((type&(FAMP|FINT)) == (FAMP|FINT)) && (maxjob=nv_getnum(JOBMAXNOD))>0) - { - while(job.numbjob >= maxjob) - { - job_lock(); - job_reap(0); - job_unlock(); - } - } -#endif /* SHOPT_BGX */ - if(type&FCOOP) - coproc_init(shp,pipes); - nv_getval(RANDNOD); -#if SHOPT_AMP - if((type&(FAMP|FINT)) == (FAMP|FINT)) - parent = sh_ntfork(shp,t,com,&jobid,ntflag); - else - parent = sh_fork(type,&jobid); - if(parent<0) - break; -#else -#if SHOPT_SPAWN -# ifdef _lib_fork - if(com) - parent = sh_ntfork(shp,t,com,&jobid,ntflag); - else - parent = sh_fork(type,&jobid); -# else - if((parent = sh_ntfork(shp,t,com,&jobid,ntflag))<=0) - break; -# endif /* _lib_fork */ - if(parent<0) - break; -#else - parent = sh_fork(type,&jobid); -#endif /* SHOPT_SPAWN */ -#endif - } - if(job.parent=parent) - /* This is the parent branch of fork - * It may or may not wait for the child - */ - { - if(pipejob==2) - { - pipejob = 1; - job_unlock(); - } - if(type&FPCL) - sh_close(shp->inpipe[0]); - if(type&(FCOOP|FAMP)) - shp->bckpid = parent; - else if(!(type&(FAMP|FPOU))) - { - if(shp->topfd > topfd) - sh_iorestore(shp,topfd,0); - if(!sh_isoption(SH_MONITOR)) - { - if(!(shp->sigflag[SIGINT]&(SH_SIGFAULT|SH_SIGOFF))) - sh_sigtrap(SIGINT); - shp->trapnote |= SH_SIGIGNORE; - } - if(execflg && shp->subshell && !shp->subshare) - { - shp->spid = parent; - job.pwlist->p_env--; - } - else if(shp->pipepid) - shp->pipepid = parent; - else - job_wait(parent); - if(!sh_isoption(SH_MONITOR)) - { - shp->trapnote &= ~SH_SIGIGNORE; - if(shp->exitval == (SH_EXITSIG|SIGINT)) - sh_fault(SIGINT); - } - } - if(type&FAMP) - { - if(sh_isstate(SH_PROFILE) || sh_isstate(SH_INTERACTIVE)) - { - /* print job number */ -#ifdef JOBS - sfprintf(sfstderr,"[%d]\t%d\n",jobid,parent); -#else - sfprintf(sfstderr,"%d\n",parent); -#endif /* JOBS */ - } - } - break; - } - else - /* - * this is the FORKED branch (child) of execute - */ - { - volatile int jmpval; - struct checkpt buff; - if(no_fork) - sh_sigreset(2); - sh_pushcontext(&buff,SH_JMPEXIT); - jmpval = sigsetjmp(buff.buff,0); - if(jmpval) - goto done; - if((type&FINT) && !sh_isstate(SH_MONITOR)) - { - /* default std input for & */ - signal(SIGINT,SIG_IGN); - signal(SIGQUIT,SIG_IGN); - if(!shp->st.ioset) - { - if(sh_close(0)>=0) - sh_chkopen(e_devnull); - } - } - sh_offstate(SH_MONITOR); - /* pipe in or out */ -#ifdef _lib_nice - if((type&FAMP) && sh_isoption(SH_BGNICE)) - nice(4); -#endif /* _lib_nice */ - if(type&FPIN) - { - sh_iorenumber(shp,shp->inpipe[0],0); - if(!(type&FPOU) || (type&FCOOP)) - sh_close(shp->inpipe[1]); - } - if(type&FPOU) - { - sh_iorenumber(shp,shp->outpipe[1],1); - sh_pclose(shp->outpipe); - } - if((type&COMMSK)!=TCOM) - error_info.line = t->fork.forkline-shp->st.firstline; - if(shp->topfd) - sh_iounsave(shp); - topfd = shp->topfd; - sh_redirect(shp,t->tre.treio,1); - if(shp->topfd > topfd) - { - job_lock(); - while((parent = vfork()) < 0) - _sh_fork(parent, 0, (int*)0); - job_fork(parent); - if(parent) - { - job_clear(); - job_post(parent,0); - job_wait(parent); - sh_iorestore(shp,topfd,SH_JMPCMD); - sh_done(shp,(shp->exitval&SH_EXITSIG)?(shp->exitval&SH_EXITMASK):0); - - } - } - if((type&COMMSK)!=TCOM) - { - /* don't clear job table for out - pipes so that jobs comand can - be used in a pipeline - */ - if(!no_fork && !(type&FPOU)) - job_clear(); - sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK)|sh_state(SH_FORKED)); - } - else if(com0) - { - sh_offoption(SH_ERREXIT); - sh_freeup(shp); - path_exec(com0,com,t->com.comset); - } - done: - sh_popcontext(&buff); - if(jmpval>SH_JMPEXIT) - siglongjmp(*shp->jmplist,jmpval); - sh_done(shp,0); - } - } - /* FALLTHROUGH */ - - case TSETIO: - { - /* - * don't create a new process, just - * save and restore io-streams - */ - pid_t pid; - int jmpval, waitall; - int simple = (t->fork.forktre->tre.tretyp&COMMSK)==TCOM; - struct checkpt buff; - if(shp->subshell) - execflg = 0; - sh_pushcontext(&buff,SH_JMPIO); - if(type&FPIN) - { - was_interactive = sh_isstate(SH_INTERACTIVE); - sh_offstate(SH_INTERACTIVE); - sh_iosave(shp,0,shp->topfd,(char*)0); - shp->pipepid = simple; - sh_iorenumber(shp,shp->inpipe[0],0); - /* - * if read end of pipe is a simple command - * treat as non-sharable to improve performance - */ - if(simple) - sfset(sfstdin,SF_PUBLIC|SF_SHARE,0); - waitall = job.waitall; - job.waitall = 0; - pid = job.parent; - } - else - error_info.line = t->fork.forkline-shp->st.firstline; - jmpval = sigsetjmp(buff.buff,0); - if(jmpval==0) - { - sh_redirect(shp,t->fork.forkio,execflg); - (t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME; - sh_exec(t->fork.forktre,flags&~simple); - } - else - sfsync(shp->outpool); - sh_popcontext(&buff); - sh_iorestore(shp,buff.topfd,jmpval); - if(buff.olist) - free_list(buff.olist); - if(type&FPIN) - { - job.waitall = waitall; - type = shp->exitval; - if(!(type&SH_EXITSIG)) - { - /* wait for remainder of pipline */ - if(shp->pipepid>1) - { - job_wait(shp->pipepid); - type = shp->exitval; - } - else - job_wait(waitall?pid:0); - if(type || !sh_isoption(SH_PIPEFAIL)) - shp->exitval = type; - } - shp->pipepid = 0; - shp->st.ioset = 0; - if(simple && was_errexit) - { - echeck = 1; - sh_onstate(SH_ERREXIT); - } - } - if(jmpval>SH_JMPIO) - siglongjmp(*shp->jmplist,jmpval); - break; - } - - case TPAR: - echeck = 1; - flags &= ~OPTIMIZE_FLAG; - if(!shp->subshell && !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && (flags&sh_state(SH_NOFORK))) - { - char *savsig; - int nsig,jmpval; - struct checkpt buff; - shp->st.otrapcom = 0; - if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) - { - nsig += sizeof(char*); - memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); - shp->st.otrapcom = (char**)savsig; - } - sh_sigreset(0); - sh_pushcontext(&buff,SH_JMPEXIT); - jmpval = sigsetjmp(buff.buff,0); - if(jmpval==0) - sh_exec(t->par.partre,flags); - sh_popcontext(&buff); - if(jmpval > SH_JMPEXIT) - siglongjmp(*shp->jmplist,jmpval); - sh_done(shp,0); - } - else - sh_subshell(t->par.partre,flags,0); - break; - - case TFIL: - { - /* - * This code sets up a pipe. - * All elements of the pipe are started by the parent. - * The last element executes in current environment - */ - int pvo[2]; /* old pipe for multi-stage */ - int pvn[2]; /* current set up pipe */ - int savepipe = pipejob; - int showme = t->tre.tretyp&FSHOWME; - pid_t savepgid = job.curpgid; - job.curpgid = 0; - if(shp->subshell) - { - if(shp->subshare) - sh_subtmpfile(0); - else - sh_subfork(); - } - shp->inpipe = pvo; - shp->outpipe = pvn; - pvo[1] = -1; - if(sh_isoption(SH_PIPEFAIL)) - job.waitall = 1; - else - job.waitall |= !pipejob && sh_isstate(SH_MONITOR); - job_lock(); - do - { -#if SHOPT_FASTPIPE - type = pipe_exec(shp,pvn,t->lst.lstlef, errorflg); -#else - /* create the pipe */ - sh_pipe(pvn); - /* execute out part of pipe no wait */ - (t->lst.lstlef)->tre.tretyp |= showme; - type = sh_exec(t->lst.lstlef, errorflg); -#endif /* SHOPT_FASTPIPE */ - pipejob=1; - /* save the pipe stream-ids */ - pvo[0] = pvn[0]; - /* close out-part of pipe */ - sh_close(pvn[1]); - /* pipeline all in one process group */ - t = t->lst.lstrit; - } - /* repeat until end of pipeline */ - while(!type && t->tre.tretyp==TFIL); - shp->inpipe = pvn; - shp->outpipe = 0; - pipejob = 2; - if(type == 0) - { - /* - * execute last element of pipeline - * in the current process - */ - ((Shnode_t*)t)->tre.tretyp |= showme; - sh_exec(t,flags); - } - else - /* execution failure, close pipe */ - sh_pclose(pvn); - if(pipejob==2) - job_unlock(); - pipejob = savepipe; -#ifdef SIGTSTP - if(!pipejob && sh_isstate(SH_MONITOR)) - tcsetpgrp(JOBTTY,shp->pid); -#endif /*SIGTSTP */ - job.curpgid = savepgid; - break; - } - - case TLST: - { - /* a list of commands are executed here */ - do - { - sh_exec(t->lst.lstlef,errorflg|OPTIMIZE); - t = t->lst.lstrit; - } - while(t->tre.tretyp == TLST); - sh_exec(t,flags); - break; - } - - case TAND: - if(type&TTEST) - skipexitset++; - if(sh_exec(t->lst.lstlef,OPTIMIZE)==0) - sh_exec(t->lst.lstrit,flags); - break; - - case TORF: - if(type&TTEST) - skipexitset++; - if(sh_exec(t->lst.lstlef,OPTIMIZE)!=0) - sh_exec(t->lst.lstrit,flags); - break; - - case TFOR: /* for and select */ - { - register char **args; - register int nargs; - register Namval_t *np; - int flag = errorflg|OPTIMIZE_FLAG; - struct dolnod *argsav=0; - struct comnod *tp; - char *cp, *trap, *nullptr = 0; - int nameref, refresh=1; - char *av[5]; -#if SHOPT_OPTIMIZE - int jmpval = ((struct checkpt*)shp->jmplist)->mode; - struct checkpt buff; - void *optlist = shp->optlist; - shp->optlist = 0; - sh_tclear(t->for_.fortre); - sh_pushcontext(&buff,jmpval); - jmpval = sigsetjmp(buff.buff,0); - if(jmpval) - goto endfor; -#endif /* SHOPT_OPTIMIZE */ - error_info.line = t->for_.forline-shp->st.firstline; - if(!(tp=t->for_.forlst)) - { - args=shp->st.dolv+1; - nargs = shp->st.dolc; - argsav=sh_arguse(shp); - } - else - { - args=sh_argbuild(shp,&argn,tp,0); - nargs = argn; - } - np = nv_open(t->for_.fornam, shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOREF); - nameref = nv_isref(np)!=0; - shp->st.loopcnt++; - cp = *args; - while(cp && shp->st.execbrk==0) - { - if(t->tre.tretyp&COMSCAN) - { - char *val; - int save_prompt; - /* reuse register */ - if(refresh) - { - sh_menu(sfstderr,nargs,args); - refresh = 0; - } - save_prompt = shp->nextprompt; - shp->nextprompt = 3; - shp->timeout = 0; - shp->exitval=sh_readline(shp,&nullptr,0,1,1000*shp->st.tmout); - shp->nextprompt = save_prompt; - if(shp->exitval||sfeof(sfstdin)||sferror(sfstdin)) - { - shp->exitval = 1; - break; - } - if(!(val=nv_getval(sh_scoped(shp,REPLYNOD)))) - continue; - else - { - if(*(cp=val) == 0) - { - refresh++; - goto check; - } - while(type = *cp++) - if(type < '0' && type > '9') - break; - if(type!=0) - type = nargs; - else - type = (int)strtol(val, (char**)0, 10)-1; - if(type<0 || type >= nargs) - cp = ""; - else - cp = args[type]; - } - } - if(nameref) - nv_offattr(np,NV_REF); - else if(nv_isattr(np, NV_ARRAY)) - nv_putsub(np,NIL(char*),0L); - nv_putval(np,cp,0); - if(nameref) - nv_setref(np,(Dt_t*)0,NV_VARNAME); - if(trap=shp->st.trap[SH_DEBUGTRAP]) - { - av[0] = (t->tre.tretyp&COMSCAN)?"select":"for"; - av[1] = t->for_.fornam; - av[2] = "in"; - av[3] = cp; - av[4] = 0; - sh_debug(shp,trap,(char*)0,(char*)0,av,0); - } - sh_exec(t->for_.fortre,flag); - flag &= ~OPTIMIZE_FLAG; - if(t->tre.tretyp&COMSCAN) - { - if((cp=nv_getval(sh_scoped(shp,REPLYNOD))) && *cp==0) - refresh++; - } - else - cp = *++args; - check: - if(shp->st.breakcnt<0) - shp->st.execbrk = (++shp->st.breakcnt !=0); - } -#if SHOPT_OPTIMIZE - endfor: - sh_popcontext(&buff); - sh_tclear(t->for_.fortre); - sh_optclear(shp,optlist); - if(jmpval) - siglongjmp(*shp->jmplist,jmpval); -#endif /*SHOPT_OPTIMIZE */ - if(shp->st.breakcnt>0) - shp->st.execbrk = (--shp->st.breakcnt !=0); - shp->st.loopcnt--; - sh_argfree(shp,argsav,0); - nv_close(np); - break; - } - - case TWH: /* while and until */ - { - volatile int r=0; - int first = OPTIMIZE_FLAG; - Shnode_t *tt = t->wh.whtre; -#if SHOPT_FILESCAN - Sfio_t *iop=0; - int savein,fd; -#endif /*SHOPT_FILESCAN*/ -#if SHOPT_OPTIMIZE - int jmpval = ((struct checkpt*)shp->jmplist)->mode; - struct checkpt buff; - void *optlist = shp->optlist; - shp->optlist = 0; - sh_tclear(t->wh.whtre); - sh_tclear(t->wh.dotre); - sh_pushcontext(&buff,jmpval); - jmpval = sigsetjmp(buff.buff,0); - if(jmpval) - goto endwhile; -#endif /* SHOPT_OPTIMIZE */ -#if SHOPT_FILESCAN - if(type==TWH && tt->tre.tretyp==TCOM && !tt->com.comarg && tt->com.comio) - { - fd = sh_redirect(shp,tt->com.comio,3); - savein = dup(0); - if(fd==0) - fd = savein; - iop = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ); - close(0); - open("/dev/null",O_RDONLY); - shp->offsets[0] = -1; - shp->offsets[1] = 0; - if(tt->com.comset) - nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN,0); - } -#endif /*SHOPT_FILESCAN */ - shp->st.loopcnt++; - while(shp->st.execbrk==0) - { -#if SHOPT_FILESCAN - if(iop) - { - if(!(shp->cur_line=sfgetr(iop,'\n',SF_STRING))) - break; - } - else -#endif /*SHOPT_FILESCAN */ - if((sh_exec(tt,first)==0)!=(type==TWH)) - break; - r = sh_exec(t->wh.dotre,first|errorflg); - if(shp->st.breakcnt<0) - shp->st.execbrk = (++shp->st.breakcnt !=0); - /* This is for the arithmetic for */ - if(shp->st.execbrk==0 && t->wh.whinc) - sh_exec((Shnode_t*)t->wh.whinc,first); - first = 0; - errorflg &= ~OPTIMIZE_FLAG; -#if SHOPT_FILESCAN - shp->offsets[0] = -1; - shp->offsets[1] = 0; -#endif /*SHOPT_FILESCAN */ - } -#if SHOPT_OPTIMIZE - endwhile: - sh_popcontext(&buff); - sh_tclear(t->wh.whtre); - sh_tclear(t->wh.dotre); - sh_optclear(shp,optlist); - if(jmpval) - siglongjmp(*shp->jmplist,jmpval); -#endif /*SHOPT_OPTIMIZE */ - if(shp->st.breakcnt>0) - shp->st.execbrk = (--shp->st.breakcnt !=0); - shp->st.loopcnt--; - shp->exitval= r; -#if SHOPT_FILESCAN - if(iop) - { - sfclose(iop); - close(0); - dup(savein); - shp->cur_line = 0; - } -#endif /*SHOPT_FILESCAN */ - break; - } - case TARITH: /* (( expression )) */ - { - register char *trap; - char *arg[4]; - error_info.line = t->ar.arline-shp->st.firstline; - arg[0] = "(("; - if(!(t->ar.arexpr->argflag&ARG_RAW)) - arg[1] = sh_macpat(shp,t->ar.arexpr,OPTIMIZE|ARG_ARITH); - else - arg[1] = t->ar.arexpr->argval; - arg[2] = "))"; - arg[3] = 0; - if(trap=shp->st.trap[SH_DEBUGTRAP]) - sh_debug(shp,trap,(char*)0, (char*)0, arg, ARG_ARITH); - if(sh_isoption(SH_XTRACE)) - { - sh_trace(NIL(char**),0); - sfprintf(sfstderr,"((%s))\n",arg[1]); - } - if(t->ar.arcomp) - shp->exitval = !arith_exec((Arith_t*)t->ar.arcomp); - else - shp->exitval = !sh_arith(arg[1]); - break; - } - - case TIF: - if(sh_exec(t->if_.iftre,OPTIMIZE)==0) - sh_exec(t->if_.thtre,flags); - else if(t->if_.eltre) - sh_exec(t->if_.eltre, flags); - else - shp->exitval=0; /* force zero exit for if-then-fi */ - break; - - case TSW: - { - Shnode_t *tt = (Shnode_t*)t; - char *trap, *r = sh_macpat(shp,tt->sw.swarg,OPTIMIZE); - error_info.line = t->sw.swline-shp->st.firstline; - t= (Shnode_t*)(tt->sw.swlst); - if(trap=shp->st.trap[SH_DEBUGTRAP]) - { - char *av[4]; - av[0] = "case"; - av[1] = r; - av[2] = "in"; - av[3] = 0; - sh_debug(shp,trap, (char*)0, (char*)0, av, 0); - } - while(t) - { - register struct argnod *rex=(struct argnod*)t->reg.regptr; - while(rex) - { - register char *s; - if(rex->argflag&ARG_MAC) - { - s = sh_macpat(shp,rex,OPTIMIZE|ARG_EXP); - while(*s=='\\' && s[1]==0) - s+=2; - } - else - s = rex->argval; - type = (rex->argflag&ARG_RAW); - if((type && strcmp(r,s)==0) || - (!type && (strmatch(r,s) - || trim_eq(r,s)))) - { - do sh_exec(t->reg.regcom,(t->reg.regflag?0:flags)); - while(t->reg.regflag && - (t=(Shnode_t*)t->reg.regnxt)); - t=0; - break; - } - else - rex=rex->argnxt.ap; - } - if(t) - t=(Shnode_t*)t->reg.regnxt; - } - break; - } - - case TTIME: - { - /* time the command */ - struct tms before,after; - const char *format = e_timeformat; - clock_t at, tm[3]; -#ifdef timeofday - struct timeval tb,ta; -#else - clock_t bt; -#endif /* timeofday */ - if(type!=TTIME) - { - sh_exec(t->par.partre,OPTIMIZE); - shp->exitval = !shp->exitval; - break; - } - if(t->par.partre) - { - long timer_on; - timer_on = sh_isstate(SH_TIMING); -#ifdef timeofday - timeofday(&tb); - times(&before); -#else - bt = times(&before); -#endif /* timeofday */ - job.waitall = 1; - sh_onstate(SH_TIMING); - sh_exec(t->par.partre,OPTIMIZE); - if(!timer_on) - sh_offstate(SH_TIMING); - job.waitall = 0; - } - else - { -#ifndef timeofday - bt = 0; -#endif /* timeofday */ - before.tms_utime = before.tms_cutime = 0; - before.tms_stime = before.tms_cstime = 0; - } -#ifdef timeofday - times(&after); - timeofday(&ta); - at = shp->lim.clk_tck*(ta.tv_sec-tb.tv_sec); - at += ((shp->lim.clk_tck*(((1000000L/2)/shp->lim.clk_tck)+(ta.tv_usec-tb.tv_usec)))/1000000L); -#else - at = times(&after) - bt; -#endif /* timeofday */ - tm[0] = at; - if(t->par.partre) - { - Namval_t *np = nv_open("TIMEFORMAT",shp->var_tree,NV_NOADD); - if(np) - { - format = nv_getval(np); - nv_close(np); - } - if(!format) - format = e_timeformat; - } - else - format = strchr(format+1,'\n')+1; - tm[1] = after.tms_utime - before.tms_utime; - tm[1] += after.tms_cutime - before.tms_cutime; - tm[2] = after.tms_stime - before.tms_stime; - tm[2] += after.tms_cstime - before.tms_cstime; - if(format && *format) - p_time(shp,sfstderr,sh_translate(format),tm); - break; - } - case TFUN: - { - register Namval_t *np; - register struct slnod *slp; - register char *fname = ((struct functnod*)t)->functnam; - register char *cp = strrchr(fname,'.'); - register Namval_t *npv=0; -#if SHOPT_NAMESPACE - if(t->tre.tretyp==TNSPACE) - { - Dt_t *root,*oldroot, *top=0; - Namval_t *oldnspace = shp->namespace; - int offset = stktell(stkp); - long optindex = shp->st.optindex; - if(cp) - errormsg(SH_DICT,ERROR_exit(1),e_ident,fname); - sfputc(stkp,'.'); - sfputr(stkp,fname,0); - np = nv_open(stkptr(stkp,offset),shp->var_base,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME); - offset = stktell(stkp); - shp->namespace = np; - if(!(root=nv_dict(np))) - { - root = dtopen(&_Nvdisc,Dtoset); - nv_putval(np,(char*)root,NV_TABLE|NV_NOFREE); - shp->st.optindex = 1; - } - if(oldnspace && dtvnext(dtvnext(shp->var_tree))) - top = dtview(shp->var_tree,0); - else if(dtvnext(shp->var_tree)) - top = dtview(shp->var_tree,0); - oldroot = shp->var_tree; - dtview(root,shp->var_base); - shp->var_tree = root; - if(top) - dtview(shp->var_tree,top); - sh_exec(t->for_.fortre,flags); - if(dtvnext(shp->var_tree)) - top = dtview(shp->var_tree,0); - shp->var_tree = oldroot; - if(top) - dtview(top,shp->var_tree); - shp->namespace = oldnspace; - shp->st.optindex = optindex; - break; - } -#endif /* SHOPT_NAMESPACE */ - /* look for discipline functions */ - error_info.line = t->funct.functline-shp->st.firstline; - /* Function names cannot be special builtin */ - if(cp || shp->prefix) - { - int offset = stktell(stkp); - if(shp->prefix) - { - cp = shp->prefix; - shp->prefix = 0; - npv = nv_open(cp,shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME); - shp->prefix = cp; - cp = fname; - } - else - { - sfwrite(stkp,fname,cp++-fname); - sfputc(stkp,0); - npv = nv_open(stkptr(stkp,offset),shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME); - } - offset = stktell(stkp); - sfprintf(stkp,"%s.%s%c",nv_name(npv),cp,0); - fname = stkptr(stkp,offset); - } - else if((np=nv_search(fname,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) - errormsg(SH_DICT,ERROR_exit(1),e_badfun,fname); -#if SHOPT_NAMESPACE - else if(shp->namespace) - { - int offset = stktell(stkp); - sfputr(stkp,nv_name(shp->namespace),-1); - sfputc(stkp,'.'); - sfputr(stkp,fname,0); - fname = stkptr(stkp,offset); - } -#endif /* SHOPT_NAMESPACE */ - np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE); - if(npv) - { - Namval_t *tp = npv; - if(!shp->mktype) - { - if(shp->typeinit) - { - if(tp=nv_open(shp->typeinit->nvname,shp->typedict,NV_IDENT|NV_NOFAIL)) - nv_close(npv); - else - tp = npv; - } - cp = nv_setdisc(tp,cp,np,(Namfun_t*)tp); - } - nv_close(tp); - if(!cp) - errormsg(SH_DICT,ERROR_exit(1),e_baddisc,fname); - } - if(np->nvalue.rp) - { - slp = (struct slnod*)np->nvenv; - sh_funstaks(slp->slchild,-1); - stakdelete(slp->slptr); - if(shp->funload) - { - free((void*)np->nvalue.rp); - np->nvalue.rp = 0; - } - - } - if(!np->nvalue.rp) - { - np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0); - memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction)); - } - if(t->funct.functstak) - { - static Dtdisc_t _Rpdisc = - { - offsetof(struct Ufunction,fname), -1, sizeof(struct Ufunction) - }; - struct functnod *fp; - slp = t->funct.functstak; - sh_funstaks(slp->slchild,1); - staklink(slp->slptr); - np->nvenv = (char*)slp; - nv_funtree(np) = (int*)(t->funct.functtre); - np->nvalue.rp->hoffset = t->funct.functloc; - np->nvalue.rp->lineno = t->funct.functline; - np->nvalue.rp->nspace = shp->namespace; - np->nvalue.rp->fname = 0; - np->nvalue.rp->fdict = shp->fun_tree; - fp = (struct functnod*)(slp+1); - if(fp->functtyp==(TFUN|FAMP)) - np->nvalue.rp->fname = fp->functnam; - nv_setsize(np,fp->functline); - nv_offattr(np,NV_FPOSIX); - if(shp->funload) - { - struct Ufunction *rp = np->nvalue.rp; - rp->np = np; - if(!shp->fpathdict) - shp->fpathdict = dtopen(&_Rpdisc,Dtbag); - if(shp->fpathdict) - dtinsert(shp->fpathdict,rp); - } - } - else - nv_unset(np); - if(type&FPOSIX) - nv_onattr(np,NV_FUNCTION|NV_FPOSIX); - else - nv_onattr(np,NV_FUNCTION); - if(type&FPIN) - nv_onattr(np,NV_FTMP); - if(type&FOPTGET) - nv_onattr(np,NV_OPTGET); - break; - } - - /* new test compound command */ - case TTST: - { - register int n; - register char *left; - int negate = (type&TNEGATE)!=0; - if(type&TTEST) - skipexitset++; - error_info.line = t->tst.tstline-shp->st.firstline; - echeck = 1; - if((type&TPAREN)==TPAREN) - { - sh_exec(t->lst.lstlef,OPTIMIZE); - n = !shp->exitval; - } - else - { - register int traceon=0; - register char *right; - register char *trap; - char *argv[6]; - n = type>>TSHIFT; - left = sh_macpat(shp,&(t->lst.lstlef->arg),OPTIMIZE); - if(type&TBINARY) - right = sh_macpat(shp,&(t->lst.lstrit->arg),((n==TEST_PEQ||n==TEST_PNE)?ARG_EXP:0)|OPTIMIZE); - if(trap=shp->st.trap[SH_DEBUGTRAP]) - argv[0] = (type&TNEGATE)?((char*)e_tstbegin):"[["; - if(sh_isoption(SH_XTRACE)) - { - traceon = sh_trace(NIL(char**),0); - sfwrite(sfstderr,e_tstbegin,(type&TNEGATE?5:3)); - } - if(type&TUNARY) - { - if(traceon) - sfprintf(sfstderr,"-%c %s",n,sh_fmtq(left)); - if(trap) - { - char unop[3]; - unop[0] = '-'; - unop[1] = n; - unop[2] = 0; - argv[1] = unop; - argv[2] = left; - argv[3] = "]]"; - argv[4] = 0; - sh_debug(shp,trap,(char*)0,(char*)0,argv, 0); - } - n = test_unop(n,left); - } - else if(type&TBINARY) - { - char *op; - int pattern = 0; - if(trap || traceon) - op = (char*)(shtab_testops+(n&037)-1)->sh_name; - type >>= TSHIFT; - if(type==TEST_PEQ || type==TEST_PNE) - pattern=ARG_EXP; - if(trap) - { - argv[1] = left; - argv[2] = op; - argv[3] = right; - argv[4] = "]]"; - argv[5] = 0; - sh_debug(shp,trap,(char*)0,(char*)0,argv, pattern); - } - n = test_binop(n,left,right); - if(traceon) - { - sfprintf(sfstderr,"%s %s ",sh_fmtq(left),op); - if(pattern) - out_pattern(sfstderr,right,-1); - else - sfputr(sfstderr,sh_fmtq(right),-1); - } - } - if(traceon) - sfwrite(sfstderr,e_tstend,4); - } - shp->exitval = ((!n)^negate); - if(!skipexitset) - exitset(); - break; - } - } - if(shp->trapnote || (shp->exitval && sh_isstate(SH_ERREXIT)) && - t && echeck) - sh_chktrap(); - /* set $_ */ - if(mainloop && com0) - { - /* store last argument here if it fits */ - static char lastarg[32]; - if(sh_isstate(SH_FORKED)) - sh_done(shp,0); - if(shp->lastarg!= lastarg && shp->lastarg) - free(shp->lastarg); - if(strlen(comn) < sizeof(lastarg)) - { - nv_onattr(L_ARGNOD,NV_NOFREE); - shp->lastarg = strcpy(lastarg,comn); - } - else - { - nv_offattr(L_ARGNOD,NV_NOFREE); - shp->lastarg = strdup(comn); - } - } - if(!skipexitset) - exitset(); - if(!(OPTIMIZE)) - { - if(sav != stkptr(stkp,0)) - stkset(stkp,sav,0); - else if(stktell(stkp)) - stkseek(stkp,0); - } - if(shp->trapnote&SH_SIGSET) - sh_exit(SH_EXITSIG|shp->lastsig); - if(was_interactive) - sh_onstate(SH_INTERACTIVE); - if(was_monitor && sh_isoption(SH_MONITOR)) - sh_onstate(SH_MONITOR); - if(was_errexit) - sh_onstate(SH_ERREXIT); - } - return(shp->exitval); -} - -int sh_run(int argn, char *argv[]) -{ - register struct dolnod *dp; - register struct comnod *t = (struct comnod*)stakalloc(sizeof(struct comnod)); - int savtop = staktell(); - char *savptr = stakfreeze(0); - Opt_t *op, *np = optctx(0, 0); - Shbltin_t bltindata; - bltindata = sh.bltindata; - op = optctx(np, 0); - memset(t, 0, sizeof(struct comnod)); - dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*)); - dp->dolnum = argn; - dp->dolbot = ARG_SPARE; - memcpy(dp->dolval+ARG_SPARE, argv, (argn+1)*sizeof(char*)); - t->comarg = (struct argnod*)dp; - if(!strchr(argv[0],'/')) - t->comnamp = (void*)nv_bfsearch(argv[0],sh.fun_tree,(Namval_t**)&t->comnamq,(char**)0); - argn=sh_exec((Shnode_t*)t,sh_isstate(SH_ERREXIT)); - optctx(op,np); - sh.bltindata = bltindata; - if(savptr!=stakptr(0)) - stakset(savptr,savtop); - else - stakseek(savtop); - return(argn); -} - -/* - * test for equality with second argument trimmed - * returns 1 if r == trim(s) otherwise 0 - */ - -static int trim_eq(register const char *r,register const char *s) -{ - register char c; - while(c = *s++) - { - if(c=='\\') - c = *s++; - if(c && c != *r++) - return(0); - } - return(*r==0); -} - -/* - * print out the command line if set -x is on - */ - -int sh_trace(register char *argv[], register int nl) -{ - Shell_t *shp = &sh; - register char *cp; - register int bracket = 0; - int decl = (nl&2); - nl &= ~2; - if(sh_isoption(SH_XTRACE)) - { - /* make this trace atomic */ - sfset(sfstderr,SF_SHARE|SF_PUBLIC,0); - if(!(cp=nv_getval(sh_scoped(shp,PS4NOD)))) - cp = "+ "; - else - { - sh_offoption(SH_XTRACE); - cp = sh_mactry(shp,cp); - sh_onoption(SH_XTRACE); - } - if(*cp) - sfputr(sfstderr,cp,-1); - if(argv) - { - char *argv0 = *argv; - nl = (nl?'\n':-1); - /* don't quote [ and [[ */ - if(*(cp=argv[0])=='[' && (!cp[1] || !cp[2]&&cp[1]=='[')) - { - sfputr(sfstderr,cp,*++argv?' ':nl); - bracket = 1; - } - while(cp = *argv++) - { - if(bracket==0 || *argv || *cp!=']') - cp = sh_fmtq(cp); - if(decl && shp->prefix && cp!=argv0 && *cp!='-') - { - if(*cp=='.' && cp[1]==0) - cp = shp->prefix; - else - sfputr(sfstderr,shp->prefix,'.'); - } - sfputr(sfstderr,cp,*argv?' ':nl); - } - sfset(sfstderr,SF_SHARE|SF_PUBLIC,1); - } - return(1); - } - return(0); -} - -/* - * This routine creates a subshell by calling fork() or vfork() - * If ((flags&COMASK)==TCOM), then vfork() is permitted - * If fork fails, the shell sleeps for exponentially longer periods - * and tries again until a limit is reached. - * SH_FORKLIM is the max period between forks - power of 2 usually. - * Currently shell tries after 2,4,8,16, and 32 seconds and then quits - * Failures cause the routine to error exit. - * Parent links to here-documents are removed by the child - * Traps are reset by the child - * The process-id of the child is returned to the parent, 0 to the child. - */ - -static void timed_out(void *handle) -{ - NOT_USED(handle); - timeout = 0; -} - - -/* - * called by parent and child after fork by sh_fork() - */ -pid_t _sh_fork(register pid_t parent,int flags,int *jobid) -{ - static long forkcnt = 1000L; - Shell_t *shp = &sh; - pid_t curpgid = job.curpgid; - pid_t postid = (flags&FAMP)?0:curpgid; - int sig,nochild; - if(parent<0) - { - sh_sigcheck(); - if((forkcnt *= 2) > 1000L*SH_FORKLIM) - { - forkcnt=1000L; - errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_nofork); - } - timeout = (void*)sh_timeradd(forkcnt, 0, timed_out, NIL(void*)); - nochild = job_wait((pid_t)1); - if(timeout) - { - if(nochild) - pause(); - else if(forkcnt>1000L) - forkcnt /= 2; - timerdel(timeout); - timeout = 0; - } - return(-1); - } - forkcnt = 1000L; - if(parent) - { - int myjob,waitall=job.waitall; - shp->nforks++; - if(job.toclear) - job_clear(); - job.waitall = waitall; -#ifdef JOBS - /* first process defines process group */ - if(sh_isstate(SH_MONITOR)) - { - /* - * errno==EPERM means that an earlier processes - * completed. Make parent the job group id. - */ - if(postid==0) - job.curpgid = parent; - if(job.jobcontrol || (flags&FAMP)) - { - if(setpgid(parent,job.curpgid)<0 && errno==EPERM) - setpgid(parent,parent); - } - } -#endif /* JOBS */ - if(!sh_isstate(SH_MONITOR) && job.waitall && postid==0) - job.curpgid = parent; - if(flags&FCOOP) - shp->cpid = parent; -#ifdef SHOPT_BGX - if(!postid && (flags&(FAMP|FINT)) == (FAMP|FINT)) - postid = 1; - myjob = job_post(parent,postid); - if(postid==1) - postid = 0; -#else - myjob = job_post(parent,postid); -#endif /* SHOPT_BGX */ - if(flags&FAMP) - job.curpgid = curpgid; - if(jobid) - *jobid = myjob; - return(parent); - } -#if !_std_malloc - vmtrace(-1); -#endif - /* This is the child process */ - if(shp->trapnote&SH_SIGTERM) - sh_exit(SH_EXITSIG|SIGTERM); - shp->nforks=0; - timerdel(NIL(void*)); -#ifdef JOBS - if(!job.jobcontrol && !(flags&FAMP)) - sh_offstate(SH_MONITOR); - if(sh_isstate(SH_MONITOR)) - { - parent = getpid(); - if(postid==0) - job.curpgid = parent; - while(setpgid(0,job.curpgid)<0 && job.curpgid!=parent) - job.curpgid = parent; -# ifdef SIGTSTP - if(job.curpgid==parent && !(flags&FAMP)) - tcsetpgrp(job.fd,job.curpgid); -# endif /* SIGTSTP */ - } -# ifdef SIGTSTP - if(job.jobcontrol) - { - signal(SIGTTIN,SIG_DFL); - signal(SIGTTOU,SIG_DFL); - signal(SIGTSTP,SIG_DFL); - } -# endif /* SIGTSTP */ - job.jobcontrol = 0; -#endif /* JOBS */ - job.toclear = 1; - shp->login_sh = 0; - sh_offoption(SH_LOGIN_SHELL); - sh_onstate(SH_FORKED); - sh_onstate(SH_NOLOG); - if (shp->fn_reset) - shp->fn_depth = shp->fn_reset = 0; -#if SHOPT_ACCT - sh_accsusp(); -#endif /* SHOPT_ACCT */ - /* Reset remaining signals to parent */ - /* except for those `lost' by trap */ - if(!(flags&FSHOWME)) - sh_sigreset(2); - shp->subshell = 0; - if((flags&FAMP) && shp->coutpipe>1) - sh_close(shp->coutpipe); - sig = shp->savesig; - shp->savesig = 0; - if(sig>0) - sh_fault(sig); - sh_sigcheck(); - return(0); -} - -pid_t sh_fork(int flags, int *jobid) -{ - register pid_t parent; - register int sig; -#if SHOPT_FASTPIPE - if(sffileno(sfstdin)<0) - { - off_t current = sfseek(sfstdin,(off_t)0,SEEK_CUR); - sfseek(sfstdin,(off_t)0,SEEK_END); - sfdisc(sfstdin,SF_POPDISC); - fcntl(sffileno(sfstdin),F_SETFD,0); - sh_iostream(0); - sfseek(sfstdin,current,SEEK_SET); - } -#endif /* SHOPT_FASTPIPE */ - if(!sh.pathlist) - path_get(""); - sfsync(NIL(Sfio_t*)); - sh.trapnote &= ~SH_SIGTERM; - job_fork(-1); - sh.savesig = -1; - while(_sh_fork(parent=fork(),flags,jobid) < 0); - sh_stats(STAT_FORKS); - sig = sh.savesig; - sh.savesig = 0; - if(sig>0) - sh_fault(sig); - job_fork(parent); - return(parent); -} - -/* - * add exports from previous scope to the new scope - */ -static void local_exports(register Namval_t *np, void *data) -{ - register Namval_t *mp; - register char *cp; - if(nv_isarray(np)) - nv_putsub(np,NIL(char*),0); - if((cp = nv_getval(np)) && (mp = nv_search(nv_name(np), sh.var_tree, NV_ADD|HASH_NOSCOPE)) && nv_isnull(mp)) - nv_putval(mp, cp, 0); -} - -/* - * This routine is used to execute the given function <fun> in a new scope - * If <fun> is NULL, then arg points to a structure containing a pointer - * to a function that will be executed in the current environment. - */ -int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) -{ - register char *trap; - register int nsig; - register Shell_t *shp = &sh; - struct dolnod *argsav=0,*saveargfor; - struct sh_scoped savst, *prevscope = shp->st.self; - struct argnod *envlist=0; - int jmpval; - volatile int r = 0; - char *savstak; - struct funenv *fp; - struct checkpt buff; - Namval_t *nspace = shp->namespace; - Dt_t *last_root = shp->last_root; - Shopt_t options = shp->options; - if(shp->fn_depth==0) - shp->glob_options = shp->options; - else - shp->options = shp->glob_options; -#if 0 - shp->st.lineno = error_info.line; -#endif - *prevscope = shp->st; - sh_offoption(SH_ERREXIT); - shp->st.prevst = prevscope; - shp->st.self = &savst; - shp->topscope = (Shscope_t*)shp->st.self; - shp->st.opterror = shp->st.optchar = 0; - shp->st.optindex = 1; - shp->st.loopcnt = 0; - if(!fun) - { - fp = (struct funenv*)arg; - shp->st.real_fun = (fp->node)->nvalue.rp; - envlist = fp->env; - } - prevscope->save_tree = shp->var_tree; - sh_scope(shp,envlist,1); - if(dtvnext(prevscope->save_tree)!= (shp->namespace?shp->var_base:0)) - { - /* eliminate parent scope */ - nv_scan(prevscope->save_tree, local_exports,(void*)0, NV_EXPORT, NV_EXPORT|NV_NOSCOPE); - } - shp->st.save_tree = shp->var_tree; - if(!fun) - { - Namval_t *np; - if(nv_isattr(fp->node,NV_TAGGED)) - sh_onoption(SH_XTRACE); - else - sh_offoption(SH_XTRACE); -#if SHOPT_NAMESPACE - if((np=(fp->node)->nvalue.rp->nspace) && np!=shp->namespace) - { - Dt_t *dt = shp->var_tree; - dtview(dt,0); - dtview(dt,nv_dict(np)); - shp->var_tree = nv_dict(np); - shp->namespace = np; - } -#endif /* SHOPT_NAMESPACE */ - } - shp->st.cmdname = argv[0]; - /* save trap table */ - if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) - { - nsig += sizeof(char*); - memcpy(savstak=stakalloc(nsig),(char*)&shp->st.trapcom[0],nsig); - } - sh_sigreset(0); - argsav = sh_argnew(shp,argv,&saveargfor); - sh_pushcontext(&buff,SH_JMPFUN); - errorpush(&buff.err,0); - error_info.id = argv[0]; - shp->st.var_local = shp->var_tree; - jmpval = sigsetjmp(buff.buff,0); - if(!fun) - { - shp->st.filename = fp->node->nvalue.rp->fname; - shp->st.funname = nv_name(fp->node); - nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); - nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); - } - if(jmpval == 0) - { - if(shp->fn_depth++ > MAXDEPTH) - { - shp->toomany = 1; - siglongjmp(*shp->jmplist,SH_JMPERRFN); - } - else if(fun) - r= (*fun)(arg); - else - { - sh_exec((Shnode_t*)(nv_funtree((fp->node))),execflg|SH_ERREXIT); - r = shp->exitval; - } - } - if(--shp->fn_depth==1 && jmpval==SH_JMPERRFN) - errormsg(SH_DICT,ERROR_exit(1),e_toodeep,argv[0]); - sh_popcontext(&buff); - if (shp->st.self != &savst) - shp->var_tree = (Dt_t*)savst.save_tree; - sh_unscope(shp); - shp->namespace = nspace; - shp->var_tree = (Dt_t*)prevscope->save_tree; - if(shp->topscope != (Shscope_t*)shp->st.self) - sh_setscope(shp->topscope); - sh_argreset(shp,argsav,saveargfor); - trap = shp->st.trapcom[0]; - shp->st.trapcom[0] = 0; - sh_sigreset(1); - if (shp->st.self != &savst) - *shp->st.self = shp->st; - shp->st = *prevscope; - shp->topscope = (Shscope_t*)prevscope; - nv_getval(sh_scoped(shp,IFSNOD)); - if(nsig) - memcpy((char*)&shp->st.trapcom[0],savstak,nsig); - shp->trapnote=0; - if(nsig) - stakset(savstak,0); - shp->options = options; - shp->last_root = last_root; - if(jmpval == SH_JMPSUB) - siglongjmp(*shp->jmplist,jmpval); - if(trap) - { - sh_trap(trap,0); - free(trap); - } - if(shp->exitval > SH_EXITSIG) - sh_fault(shp->exitval&SH_EXITMASK); - if(jmpval > SH_JMPFUN) - { - sh_chktrap(); - siglongjmp(*shp->jmplist,jmpval); - } - return(r); -} - -static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct argnod *envlist,int execflg) -{ - struct funenv fun; - char *fname = nv_getval(SH_FUNNAMENOD); - struct Level *lp =(struct Level*)(SH_LEVELNOD->nvfun); - int level, pipepid=shp->pipepid; - shp->pipepid = 0; - sh_stats(STAT_FUNCT); - if(!lp->hdr.disc) - lp = init_level(0); - if((struct sh_scoped*)shp->topscope != shp->st.self) - sh_setscope(shp->topscope); - level = lp->maxlevel = shp->dot_depth + shp->fn_depth+1; - SH_LEVELNOD->nvalue.s = lp->maxlevel; - shp->st.lineno = error_info.line; - if(nv_isattr(np,NV_FPOSIX)) - { - char *save; - int loopcnt = shp->st.loopcnt; - shp->posix_fun = np; - save = argv[-1]; - argv[-1] = 0; - shp->st.funname = nv_name(np); - nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE); - opt_info.index = opt_info.offset = 0; - error_info.errors = 0; - shp->st.loopcnt = 0; - b_dot_cmd(argn+1,argv-1,&shp->bltindata); - shp->st.loopcnt = loopcnt; - argv[-1] = save; - } - else - { - fun.env = envlist; - fun.node = np; - sh_funscope(argn,argv,0,&fun,execflg); - } - if(level-- != nv_getnum(SH_LEVELNOD)) - { - Shscope_t *sp = sh_getscope(0,SEEK_END); - sh_setscope(sp); - } - lp->maxlevel = level; - SH_LEVELNOD->nvalue.s = lp->maxlevel; -#if 0 - nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); -#else - nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE); -#endif - nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); - shp->pipepid = pipepid; -} - -/* - * external interface to execute a function without arguments - * <np> is the function node - * If <nq> is not-null, then sh.name and sh.subscript will be set - */ -int sh_fun(Namval_t *np, Namval_t *nq, char *argv[]) -{ - Shell_t *shp = &sh; - register int offset; - register char *base; - Namval_t node; - struct Namref nr; - long mode; - char *prefix = shp->prefix; - int n=0; - char *av[2]; - Fcin_t save; - fcsave(&save); - if((offset=staktell())>0) - base=stakfreeze(0); - shp->prefix = 0; - if(!argv) - { - argv = av; - argv[1]=0; - } - argv[0] = nv_name(np); - while(argv[n]) - n++; - if(nq) - mode = set_instance(shp,nq,&node, &nr); - if(is_abuiltin(np)) - { - int jmpval; - struct checkpt buff; - Shbltin_t *bp = &sh.bltindata; - sh_pushcontext(&buff,SH_JMPCMD); - jmpval = sigsetjmp(buff.buff,1); - if(jmpval == 0) - { - bp->bnode = np; - bp->ptr = nv_context(np); - errorpush(&buff.err,0); - error_info.id = argv[0]; - opt_info.index = opt_info.offset = 0; - opt_info.disc = 0; - sh.exitval = 0; - sh.exitval = (*funptr(np))(n,argv,(void*)bp); - } - sh_popcontext(&buff); - if(jmpval>SH_JMPCMD) - siglongjmp(*sh.jmplist,jmpval); - } - else - sh_funct(shp,np,n,argv,(struct argnod*)0,sh_isstate(SH_ERREXIT)); - if(nq) - unset_instance(nq, &node, &nr, mode); - fcrestore(&save); - if(offset>0) - stakset(base,offset); - shp->prefix = prefix; - return(sh.exitval); -} - -/* - * This dummy routine is called by built-ins that do recursion - * on the file system (chmod, chgrp, chown). It causes - * the shell to invoke the non-builtin version in this case - */ -int cmdrecurse(int argc, char* argv[], int ac, char* av[]) -{ - NOT_USED(argc); - NOT_USED(argv[0]); - NOT_USED(ac); - NOT_USED(av[0]); - return(SH_RUNPROG); -} - -/* - * set up pipe for cooperating process - */ -static void coproc_init(Shell_t *shp, int pipes[]) -{ - int outfd; - if(shp->coutpipe>=0 && shp->cpid) - errormsg(SH_DICT,ERROR_exit(1),e_pexists); - shp->cpid = 0; - if(shp->cpipe[0]<=0 || shp->cpipe[1]<=0) - { - /* first co-process */ - sh_pclose(shp->cpipe); - sh_pipe(shp->cpipe); - if((outfd=shp->cpipe[1]) < 10) - { - int fd=fcntl(shp->cpipe[1],F_DUPFD,10); - if(fd>=10) - { - shp->fdstatus[fd] = (shp->fdstatus[outfd]&~IOCLEX); - close(outfd); - shp->fdstatus[outfd] = IOCLOSE; - shp->cpipe[1] = fd; - } - } - if(fcntl(*shp->cpipe,F_SETFD,FD_CLOEXEC)>=0) - shp->fdstatus[shp->cpipe[0]] |= IOCLEX; - shp->fdptrs[shp->cpipe[0]] = shp->cpipe; - - if(fcntl(shp->cpipe[1],F_SETFD,FD_CLOEXEC) >=0) - shp->fdstatus[shp->cpipe[1]] |= IOCLEX; - } - shp->outpipe = shp->cpipe; - sh_pipe(shp->inpipe=pipes); - shp->coutpipe = shp->inpipe[1]; - shp->fdptrs[shp->coutpipe] = &shp->coutpipe; - if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0) - shp->fdstatus[shp->outpipe[0]] |= IOCLEX; -} - -#if SHOPT_SPAWN - - -#if SHOPT_AMP || !defined(_lib_fork) -/* - * print out function definition - */ -static void print_fun(register Namval_t* np, void *data) -{ - register char *format; - NOT_USED(data); - if(!is_afunction(np) || !np->nvalue.ip) - return; - if(nv_isattr(np,NV_FPOSIX)) - format="%s()\n{ "; - else - format="function %s\n{ "; - sfprintf(sfstdout,format,nv_name(np)); - sh_deparse(sfstdout,(Shnode_t*)(nv_funtree(np)),0); - sfwrite(sfstdout,"}\n",2); -} - -/* - * create a shell script consisting of t->fork.forktre and execute it - */ -static int run_subshell(const Shnode_t *t,pid_t grp) -{ - static const char prolog[] = "(print $(typeset +A);set; typeset -p; print .sh.dollar=$$;set +o)"; - register int i, fd, trace = sh_isoption(SH_XTRACE); - int pin,pout; - pid_t pid; - char *arglist[2], *envlist[2], devfd[12], *cp; - Sfio_t *sp = sftmp(0); - envlist[0] = "_=" SH_ID; - envlist[1] = 0; - arglist[0] = error_info.id?error_info.id:sh.shname; - if(*arglist[0]=='-') - arglist[0]++; - arglist[1] = devfd; - strncpy(devfd,e_devfdNN,sizeof(devfd)); - arglist[2] = 0; - sfstack(sfstdout,sp); - if(trace) - sh_offoption(SH_XTRACE); - sfwrite(sfstdout,"typeset -A -- ",14); - sh_trap(prolog,0); - nv_scan(sh.fun_tree, print_fun, (void*)0,0, 0); - if(sh.st.dolc>0) - { - /* pass the positional parameters */ - char **argv = sh.st.dolv+1; - sfwrite(sfstdout,"set --",6); - while(*argv) - sfprintf(sfstdout," %s",sh_fmtq(*argv++)); - sfputc(sfstdout,'\n'); - } - pin = (sh.inpipe?sh.inpipe[1]:0); - pout = (sh.outpipe?sh.outpipe[0]:0); - for(i=3; i < 10; i++) - { - if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout) - { - sfprintf(sfstdout,"exec %d<&%d\n",i,i); - fcntl(i,F_SETFD,0); - } - } - sfprintf(sfstdout,"LINENO=%d\n",t->fork.forkline); - if(trace) - { - sfwrite(sfstdout,"set -x\n",7); - sh_onoption(SH_XTRACE); - } - sfstack(sfstdout,NIL(Sfio_t*)); - sh_deparse(sp,t->fork.forktre,0); - sfseek(sp,(Sfoff_t)0,SEEK_SET); - fd = sh_dup(sffileno(sp)); - cp = devfd+8; - if(fd>9) - *cp++ = '0' + (fd/10); - *cp++ = '0' + fd%10; - *cp = 0; - sfclose(sp); - sfsync(NIL(Sfio_t*)); - if(!sh.shpath) - sh.shpath = pathshell(); - pid = spawnveg(sh.shpath,arglist,envlist,grp); - close(fd); - for(i=3; i < 10; i++) - { - if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout) - fcntl(i,F_SETFD,FD_CLOEXEC); - } - if(pid <=0) - errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arglist[0]); - return(pid); -} -#endif /* !_lib_fork */ - -static void sigreset(int mode) -{ - register char *trap; - register int sig=sh.st.trapmax; - while(sig-- > 0) - { - if((trap=sh.st.trapcom[sig]) && *trap==0) - signal(sig,mode?sh_fault:SIG_IGN); - } -} - -/* - * A combined fork/exec for systems with slow or non-existent fork() - */ -static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,int flag) -{ - static pid_t spawnpid; - static int savetype; - static int savejobid __unused; - struct checkpt buff; - int otype=0, jmpval; - volatile int jobwasset=0, scope=0, sigwasset=0; - char **arge, *path; - volatile pid_t grp = 0; - Pathcomp_t *pp; - if(flag) - { - otype = savetype; - savetype=0; - } -# if SHOPT_AMP || !defined(_lib_fork) - if(!argv) - { - register Shnode_t *tchild = t->fork.forktre; - int optimize=0; - otype = t->tre.tretyp; - savetype = otype; - spawnpid = 0; -# ifndef _lib_fork - if((tchild->tre.tretyp&COMMSK)==TCOM) - { - Namval_t *np = (Namval_t*)(tchild->com.comnamp); - if(np) - { - path = nv_name(np); - if(!nv_isattr(np,BLT_ENV)) - np=0; - else if(strcmp(path,"echo")==0 || memcmp(path,"print",5)==0) - np=0; - } - else if(!tchild->com.comarg) - optimize=1; - else if(tchild->com.comtyp&COMSCAN) - { - if(tchild->com.comarg->argflag&ARG_RAW) - path = tchild->com.comarg->argval; - else - path = 0; - } - else - path = ((struct dolnod*)tchild->com.comarg)->dolval[ARG_SPARE]; - if(!np && path && !nv_search(path,shp->fun_tree,0)) - optimize=1; - } -# endif - sh_pushcontext(&buff,SH_JMPIO); - jmpval = sigsetjmp(buff.buff,0); - { - if((otype&FINT) && !sh_isstate(SH_MONITOR)) - { - signal(SIGQUIT,SIG_IGN); - signal(SIGINT,SIG_IGN); - if(!shp->st.ioset) - { - sh_iosave(shp,0,buff.topfd,(char*)0); - sh_iorenumber(shp,sh_chkopen(e_devnull),0); - } - } - if(otype&FPIN) - { - int fd = shp->inpipe[1]; - sh_iosave(shp,0,buff.topfd,(char*)0); - sh_iorenumber(shp,shp->inpipe[0],0); - if(fd>=0 && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(fd,F_SETFD,FD_CLOEXEC)>=0) - shp->fdstatus[fd] |= IOCLEX; - } - if(otype&FPOU) - { - sh_iosave(shp,1,buff.topfd,(char*)0); - sh_iorenumber(shp,sh_dup(shp->outpipe[1]),1); - if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0) - shp->fdstatus[shp->outpipe[0]] |= IOCLEX; - } - - if(t->fork.forkio) - sh_redirect(shp,t->fork.forkio,0); - if(optimize==0) - { -#ifdef SIGTSTP - if(job.jobcontrol) - { - signal(SIGTTIN,SIG_DFL); - signal(SIGTTOU,SIG_DFL); - } -#endif /* SIGTSTP */ -#ifdef JOBS - if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP))) - { - if((otype&FAMP) || job.curpgid==0) - grp = 1; - else - grp = job.curpgid; - } -#endif /* JOBS */ - spawnpid = run_subshell(t,grp); - } - else - { - sh_exec(tchild,SH_NTFORK); - if(jobid) - *jobid = savejobid; - } - } - sh_popcontext(&buff); - if((otype&FINT) && !sh_isstate(SH_MONITOR)) - { - signal(SIGQUIT,sh_fault); - signal(SIGINT,sh_fault); - } - if((otype&FPIN) && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(shp->inpipe[1],F_SETFD,FD_CLOEXEC)>=0) - shp->fdstatus[shp->inpipe[1]] &= ~IOCLEX; - if(t->fork.forkio || otype) - sh_iorestore(shp,buff.topfd,jmpval); - if(optimize==0) - { -#ifdef SIGTSTP - if(job.jobcontrol) - { - signal(SIGTTIN,SIG_IGN); - signal(SIGTTOU,SIG_IGN); - } -#endif /* SIGTSTP */ - if(spawnpid>0) - _sh_fork(spawnpid,otype,jobid); - if(grp>0 && !(otype&FAMP)) - { - while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid) - job.curpgid = spawnpid; - } - } - savetype=0; - if(jmpval>SH_JMPIO) - siglongjmp(*shp->jmplist,jmpval); - if(spawnpid<0 && (otype&FCOOP)) - { - sh_close(shp->coutpipe); - sh_close(shp->cpipe[1]); - shp->cpipe[1] = -1; - shp->coutpipe = -1; - } - shp->exitval = 0; - return(spawnpid); - } -# endif /* !_lib_fork */ - sh_pushcontext(&buff,SH_JMPCMD); - errorpush(&buff.err,ERROR_SILENT); - jmpval = sigsetjmp(buff.buff,0); - if(jmpval == 0) - { - if((otype&FINT) && !sh_isstate(SH_MONITOR)) - { - signal(SIGQUIT,SIG_IGN); - signal(SIGINT,SIG_IGN); - } - spawnpid = -1; - if(t->com.comio) - sh_redirect(shp,t->com.comio,0); - error_info.id = *argv; - if(t->com.comset) - { - scope++; - sh_scope(shp,t->com.comset,0); - } - if(!strchr(path=argv[0],'/')) - { - Namval_t *np; - if((np=nv_search(path,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp) - path = nv_getval(np); - else if(path_absolute(path,NIL(Pathcomp_t*))) - { - path = stkptr(shp->stk,PATH_OFFSET); - stkfreeze(shp->stk,0); - } - else - { - pp=path_get(path); - while(pp) - { - if(pp->len==1 && *pp->name=='.') - break; - pp = pp->next; - } - if(!pp) - path = 0; - } - } - else if(sh_isoption(SH_RESTRICTED)) - errormsg(SH_DICT,ERROR_exit(1),e_restricted,path); - if(!path) - { - spawnpid = -1; - goto fail; - } - arge = sh_envgen(); - shp->exitval = 0; -#ifdef SIGTSTP - if(job.jobcontrol) - { - signal(SIGTTIN,SIG_DFL); - signal(SIGTTOU,SIG_DFL); - jobwasset++; - } -#endif /* SIGTSTP */ -#ifdef JOBS - if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP))) - { - if((otype&FAMP) || job.curpgid==0) - grp = 1; - else - grp = job.curpgid; - } -#endif /* JOBS */ - - sfsync(NIL(Sfio_t*)); - sigreset(0); /* set signals to ignore */ - sigwasset++; - /* find first path that has a library component */ - for(pp=path_get(argv[0]); pp && !pp->lib ; pp=pp->next); - spawnpid = path_spawn(path,argv,arge,pp,(grp<<1)|1); - if(spawnpid < 0 && errno==ENOEXEC) - { - char *devfd; - int fd = open(path,O_RDONLY); - argv[-1] = argv[0]; - argv[0] = path; - if(fd>=0) - { - struct stat statb; - sfprintf(sh.strbuf,"/dev/fd/%d",fd); - if(stat(devfd=sfstruse(sh.strbuf),&statb)>=0) - argv[0] = devfd; - } - if(!shp->shpath) - shp->shpath = pathshell(); - spawnpid = path_spawn(shp->shpath,&argv[-1],arge,pp,(grp<<1)|1); - if(fd>=0) - close(fd); - argv[0] = argv[-1]; - } - fail: - if(spawnpid < 0) switch(errno=shp->path_err) - { - case ENOENT: - errormsg(SH_DICT,ERROR_system(ERROR_NOENT),e_found+4); - /* FALLTHROUGH */ - default: - errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4); - } - } - else - exitset(); - sh_popcontext(&buff); - if(buff.olist) - free_list(buff.olist); -#ifdef SIGTSTP - if(jobwasset) - { - signal(SIGTTIN,SIG_IGN); - signal(SIGTTOU,SIG_IGN); - } -#endif /* SIGTSTP */ - if(sigwasset) - sigreset(1); /* restore ignored signals */ - if(scope) - { - sh_unscope(shp); - if(jmpval==SH_JMPSCRIPT) - nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN,0); - } - if(t->com.comio) - sh_iorestore(shp,buff.topfd,jmpval); - if(jmpval>SH_JMPCMD) - siglongjmp(*shp->jmplist,jmpval); - if(spawnpid>0) - { - _sh_fork(spawnpid,otype,jobid); -#ifdef JOBS - if(grp==1) - job.curpgid = spawnpid; -# ifdef SIGTSTP - if(grp>0 && !(otype&FAMP)) - { - while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid) - job.curpgid = spawnpid; - } -# endif /* SIGTSTP */ -#endif /* JOBS */ - savejobid = *jobid; - if(otype) - return(0); - } - return(spawnpid); -} - -# ifdef _was_lib_fork -# define _lib_fork 1 -# endif -# ifndef _lib_fork - pid_t fork(void) - { - errormsg(SH_DICT,ERROR_exit(3),e_notimp,"fork"); - return(-1); - } -# endif /* _lib_fork */ -#endif /* SHOPT_SPAWN */ |