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