147112Sbostic /*- 260704Sbostic * Copyright (c) 1993 360704Sbostic * The Regents of the University of California. All rights reserved. 447112Sbostic * 547112Sbostic * This code is derived from software contributed to Berkeley by 647112Sbostic * Kenneth Almquist. 747112Sbostic * 860703Sbostic * %sccs.include.redist.c% 947112Sbostic */ 1047112Sbostic 1147112Sbostic #ifndef lint 12*69402Schristos static char sccsid[] = "@(#)eval.c 8.6 (Berkeley) 05/13/95"; 1347112Sbostic #endif /* not lint */ 1447112Sbostic 1569272Schristos #include <signal.h> 1669272Schristos #include <unistd.h> 1769272Schristos 1847112Sbostic /* 1947112Sbostic * Evaluate a command. 2047112Sbostic */ 2147112Sbostic 2247112Sbostic #include "shell.h" 2347112Sbostic #include "nodes.h" 2447112Sbostic #include "syntax.h" 2547112Sbostic #include "expand.h" 2647112Sbostic #include "parser.h" 2747112Sbostic #include "jobs.h" 2847112Sbostic #include "eval.h" 2947112Sbostic #include "builtins.h" 3047112Sbostic #include "options.h" 3147112Sbostic #include "exec.h" 3247112Sbostic #include "redir.h" 3347112Sbostic #include "input.h" 3447112Sbostic #include "output.h" 3547112Sbostic #include "trap.h" 3647112Sbostic #include "var.h" 3747112Sbostic #include "memalloc.h" 3847112Sbostic #include "error.h" 3969272Schristos #include "show.h" 4047112Sbostic #include "mystring.h" 4169272Schristos #ifndef NO_HISTORY 4255245Smarc #include "myhistedit.h" 4369272Schristos #endif 4447112Sbostic 4547112Sbostic 4647112Sbostic /* flags in argument to evaltree */ 4747112Sbostic #define EV_EXIT 01 /* exit after evaluating tree */ 4847112Sbostic #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 4947112Sbostic #define EV_BACKCMD 04 /* command executing within back quotes */ 5047112Sbostic 5147112Sbostic 5247112Sbostic /* reasons for skipping commands (see comment on breakcmd routine) */ 5347112Sbostic #define SKIPBREAK 1 5447112Sbostic #define SKIPCONT 2 5547112Sbostic #define SKIPFUNC 3 5647112Sbostic 5747112Sbostic MKINIT int evalskip; /* set if we are skipping commands */ 5847112Sbostic STATIC int skipcount; /* number of levels to skip */ 5947112Sbostic MKINIT int loopnest; /* current loop nesting level */ 6047112Sbostic int funcnest; /* depth of function calls */ 6147112Sbostic 6247112Sbostic 6347112Sbostic char *commandname; 6447112Sbostic struct strlist *cmdenviron; 6547112Sbostic int exitstatus; /* exit status of last command */ 6647112Sbostic 6747112Sbostic 6869272Schristos STATIC void evalloop __P((union node *)); 6969272Schristos STATIC void evalfor __P((union node *)); 7069272Schristos STATIC void evalcase __P((union node *, int)); 7169272Schristos STATIC void evalsubshell __P((union node *, int)); 7269272Schristos STATIC void expredir __P((union node *)); 7369272Schristos STATIC void evalpipe __P((union node *)); 7469272Schristos STATIC void evalcommand __P((union node *, int, struct backcmd *)); 7569272Schristos STATIC void prehash __P((union node *)); 7647112Sbostic 7747112Sbostic 7847112Sbostic /* 7947112Sbostic * Called to reset things after an exception. 8047112Sbostic */ 8147112Sbostic 8247112Sbostic #ifdef mkinit 8347112Sbostic INCLUDE "eval.h" 8447112Sbostic 8547112Sbostic RESET { 8647112Sbostic evalskip = 0; 8747112Sbostic loopnest = 0; 8847112Sbostic funcnest = 0; 8947112Sbostic } 9047112Sbostic 9147112Sbostic SHELLPROC { 9247112Sbostic exitstatus = 0; 9347112Sbostic } 9447112Sbostic #endif 9547112Sbostic 9647112Sbostic 9747112Sbostic 9847112Sbostic /* 9947292Smarc * The eval commmand. 10047112Sbostic */ 10147112Sbostic 10269272Schristos int 10347292Smarc evalcmd(argc, argv) 10469272Schristos int argc; 10547292Smarc char **argv; 10647292Smarc { 10747292Smarc char *p; 10847292Smarc char *concat; 10947292Smarc char **ap; 11047112Sbostic 11147292Smarc if (argc > 1) { 11247292Smarc p = argv[1]; 11347292Smarc if (argc > 2) { 11447292Smarc STARTSTACKSTR(concat); 11547292Smarc ap = argv + 2; 11647292Smarc for (;;) { 11747292Smarc while (*p) 11847292Smarc STPUTC(*p++, concat); 11947292Smarc if ((p = *ap++) == NULL) 12047292Smarc break; 12147292Smarc STPUTC(' ', concat); 12247292Smarc } 12347292Smarc STPUTC('\0', concat); 12447292Smarc p = grabstackstr(concat); 12547292Smarc } 12647292Smarc evalstring(p); 12747292Smarc } 12847292Smarc return exitstatus; 12947112Sbostic } 13047112Sbostic 13147112Sbostic 13247112Sbostic /* 13347112Sbostic * Execute a command or commands contained in a string. 13447112Sbostic */ 13547112Sbostic 13647112Sbostic void 13747112Sbostic evalstring(s) 13847112Sbostic char *s; 13947112Sbostic { 14047112Sbostic union node *n; 14147112Sbostic struct stackmark smark; 14247112Sbostic 14347112Sbostic setstackmark(&smark); 14447112Sbostic setinputstring(s, 1); 14547112Sbostic while ((n = parsecmd(0)) != NEOF) { 14647112Sbostic evaltree(n, 0); 14747112Sbostic popstackmark(&smark); 14847112Sbostic } 14947112Sbostic popfile(); 15047112Sbostic popstackmark(&smark); 15147112Sbostic } 15247112Sbostic 15347112Sbostic 15447112Sbostic 15547112Sbostic /* 15647112Sbostic * Evaluate a parse tree. The value is left in the global variable 15747112Sbostic * exitstatus. 15847112Sbostic */ 15947112Sbostic 16047112Sbostic void 16147112Sbostic evaltree(n, flags) 16247112Sbostic union node *n; 16369272Schristos int flags; 16469272Schristos { 16547112Sbostic if (n == NULL) { 16647112Sbostic TRACE(("evaltree(NULL) called\n")); 16755245Smarc exitstatus = 0; 16855245Smarc goto out; 16947112Sbostic } 17069272Schristos #ifndef NO_HISTORY 17155245Smarc displayhist = 1; /* show history substitutions done with fc */ 17269272Schristos #endif 17369272Schristos TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); 17447112Sbostic switch (n->type) { 17547112Sbostic case NSEMI: 17647112Sbostic evaltree(n->nbinary.ch1, 0); 17747112Sbostic if (evalskip) 17847112Sbostic goto out; 17947112Sbostic evaltree(n->nbinary.ch2, flags); 18047112Sbostic break; 18147112Sbostic case NAND: 18247112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 18347112Sbostic if (evalskip || exitstatus != 0) 18447112Sbostic goto out; 18547112Sbostic evaltree(n->nbinary.ch2, flags); 18647112Sbostic break; 18747112Sbostic case NOR: 18847112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 18947112Sbostic if (evalskip || exitstatus == 0) 19047112Sbostic goto out; 19147112Sbostic evaltree(n->nbinary.ch2, flags); 19247112Sbostic break; 19347112Sbostic case NREDIR: 19447112Sbostic expredir(n->nredir.redirect); 19547112Sbostic redirect(n->nredir.redirect, REDIR_PUSH); 19647112Sbostic evaltree(n->nredir.n, flags); 19747112Sbostic popredir(); 19847112Sbostic break; 19947112Sbostic case NSUBSHELL: 20047112Sbostic evalsubshell(n, flags); 20147112Sbostic break; 20247112Sbostic case NBACKGND: 20347112Sbostic evalsubshell(n, flags); 20447112Sbostic break; 20547982Smarc case NIF: { 206*69402Schristos int status; 20747982Smarc 20847112Sbostic evaltree(n->nif.test, EV_TESTED); 209*69402Schristos status = exitstatus; 210*69402Schristos exitstatus = 0; 21147112Sbostic if (evalskip) 21247112Sbostic goto out; 213*69402Schristos if (status == 0) 21447112Sbostic evaltree(n->nif.ifpart, flags); 215*69402Schristos else if (n->nif.elsepart) 21647112Sbostic evaltree(n->nif.elsepart, flags); 21747112Sbostic break; 21847982Smarc } 21947112Sbostic case NWHILE: 22047112Sbostic case NUNTIL: 22147112Sbostic evalloop(n); 22247112Sbostic break; 22347112Sbostic case NFOR: 22447112Sbostic evalfor(n); 22547112Sbostic break; 22647112Sbostic case NCASE: 22747112Sbostic evalcase(n, flags); 22847112Sbostic break; 22947112Sbostic case NDEFUN: 23047112Sbostic defun(n->narg.text, n->narg.next); 23147112Sbostic exitstatus = 0; 23247112Sbostic break; 23353175Smarc case NNOT: 23453175Smarc evaltree(n->nnot.com, EV_TESTED); 23553175Smarc exitstatus = !exitstatus; 23653175Smarc break; 23753175Smarc 23847112Sbostic case NPIPE: 23947112Sbostic evalpipe(n); 24047112Sbostic break; 24147112Sbostic case NCMD: 24247112Sbostic evalcommand(n, flags, (struct backcmd *)NULL); 24347112Sbostic break; 24447112Sbostic default: 24547112Sbostic out1fmt("Node type = %d\n", n->type); 24647112Sbostic flushout(&output); 24747112Sbostic break; 24847112Sbostic } 24947112Sbostic out: 25047112Sbostic if (pendingsigs) 25147112Sbostic dotrap(); 25247112Sbostic if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 25347112Sbostic exitshell(exitstatus); 25447112Sbostic } 25547112Sbostic 25647112Sbostic 25747112Sbostic STATIC void 25847112Sbostic evalloop(n) 25947112Sbostic union node *n; 26069391Schristos { 26147112Sbostic int status; 26247112Sbostic 26347112Sbostic loopnest++; 26447112Sbostic status = 0; 26547112Sbostic for (;;) { 26647112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 26747112Sbostic if (evalskip) { 26847112Sbostic skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 26947112Sbostic evalskip = 0; 27047112Sbostic continue; 27147112Sbostic } 27247112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 27347112Sbostic evalskip = 0; 27447112Sbostic break; 27547112Sbostic } 27647112Sbostic if (n->type == NWHILE) { 27747112Sbostic if (exitstatus != 0) 27847112Sbostic break; 27947112Sbostic } else { 28047112Sbostic if (exitstatus == 0) 28147112Sbostic break; 28247112Sbostic } 28347112Sbostic evaltree(n->nbinary.ch2, 0); 28447112Sbostic status = exitstatus; 28547112Sbostic if (evalskip) 28647112Sbostic goto skipping; 28747112Sbostic } 28847112Sbostic loopnest--; 28947112Sbostic exitstatus = status; 29047112Sbostic } 29147112Sbostic 29247112Sbostic 29347112Sbostic 29447112Sbostic STATIC void 29547112Sbostic evalfor(n) 29669391Schristos union node *n; 29769391Schristos { 29847112Sbostic struct arglist arglist; 29947112Sbostic union node *argp; 30047112Sbostic struct strlist *sp; 30147112Sbostic struct stackmark smark; 30247112Sbostic 30347112Sbostic setstackmark(&smark); 30447112Sbostic arglist.lastp = &arglist.list; 30547112Sbostic for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 30653298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 30747112Sbostic if (evalskip) 30847112Sbostic goto out; 30947112Sbostic } 31047112Sbostic *arglist.lastp = NULL; 31147112Sbostic 31247112Sbostic exitstatus = 0; 31347112Sbostic loopnest++; 31447112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 31547112Sbostic setvar(n->nfor.var, sp->text, 0); 31647112Sbostic evaltree(n->nfor.body, 0); 31747112Sbostic if (evalskip) { 31847112Sbostic if (evalskip == SKIPCONT && --skipcount <= 0) { 31947112Sbostic evalskip = 0; 32047112Sbostic continue; 32147112Sbostic } 32247112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 32347112Sbostic evalskip = 0; 32447112Sbostic break; 32547112Sbostic } 32647112Sbostic } 32747112Sbostic loopnest--; 32847112Sbostic out: 32947112Sbostic popstackmark(&smark); 33047112Sbostic } 33147112Sbostic 33247112Sbostic 33347112Sbostic 33447112Sbostic STATIC void 33547112Sbostic evalcase(n, flags) 33647112Sbostic union node *n; 33769272Schristos int flags; 33869272Schristos { 33947112Sbostic union node *cp; 34047112Sbostic union node *patp; 34147112Sbostic struct arglist arglist; 34247112Sbostic struct stackmark smark; 34347112Sbostic 34447112Sbostic setstackmark(&smark); 34547112Sbostic arglist.lastp = &arglist.list; 34653298Smarc expandarg(n->ncase.expr, &arglist, EXP_TILDE); 34747112Sbostic for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 34847112Sbostic for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 34947112Sbostic if (casematch(patp, arglist.list->text)) { 35047112Sbostic if (evalskip == 0) { 35147112Sbostic evaltree(cp->nclist.body, flags); 35247112Sbostic } 35347112Sbostic goto out; 35447112Sbostic } 35547112Sbostic } 35647112Sbostic } 35747112Sbostic out: 35847112Sbostic popstackmark(&smark); 35947112Sbostic } 36047112Sbostic 36147112Sbostic 36247112Sbostic 36347112Sbostic /* 36447112Sbostic * Kick off a subshell to evaluate a tree. 36547112Sbostic */ 36647112Sbostic 36747112Sbostic STATIC void 36847112Sbostic evalsubshell(n, flags) 36947112Sbostic union node *n; 37069272Schristos int flags; 37169272Schristos { 37247112Sbostic struct job *jp; 37347112Sbostic int backgnd = (n->type == NBACKGND); 37447112Sbostic 37547112Sbostic expredir(n->nredir.redirect); 37647112Sbostic jp = makejob(n, 1); 37747112Sbostic if (forkshell(jp, n, backgnd) == 0) { 37847112Sbostic if (backgnd) 37947112Sbostic flags &=~ EV_TESTED; 38047112Sbostic redirect(n->nredir.redirect, 0); 38147112Sbostic evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 38247112Sbostic } 38347112Sbostic if (! backgnd) { 38447112Sbostic INTOFF; 38547112Sbostic exitstatus = waitforjob(jp); 38647112Sbostic INTON; 38747112Sbostic } 38847112Sbostic } 38947112Sbostic 39047112Sbostic 39147112Sbostic 39247112Sbostic /* 39347112Sbostic * Compute the names of the files in a redirection list. 39447112Sbostic */ 39547112Sbostic 39647112Sbostic STATIC void 39747112Sbostic expredir(n) 39847112Sbostic union node *n; 39969391Schristos { 40047112Sbostic register union node *redir; 40147112Sbostic 40247112Sbostic for (redir = n ; redir ; redir = redir->nfile.next) { 40369272Schristos struct arglist fn; 40469272Schristos fn.lastp = &fn.list; 40569272Schristos switch (redir->type) { 40669272Schristos case NFROM: 40769272Schristos case NTO: 40869272Schristos case NAPPEND: 40953298Smarc expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 41047112Sbostic redir->nfile.expfname = fn.list->text; 41169272Schristos break; 41269272Schristos case NFROMFD: 41369272Schristos case NTOFD: 41469272Schristos if (redir->ndup.vname) { 41569272Schristos expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 41669272Schristos fixredir(redir, fn.list->text, 1); 41769272Schristos } 41869272Schristos break; 41947112Sbostic } 42047112Sbostic } 42147112Sbostic } 42247112Sbostic 42347112Sbostic 42447112Sbostic 42547112Sbostic /* 42647112Sbostic * Evaluate a pipeline. All the processes in the pipeline are children 42747112Sbostic * of the process creating the pipeline. (This differs from some versions 42847112Sbostic * of the shell, which make the last process in a pipeline the parent 42947112Sbostic * of all the rest.) 43047112Sbostic */ 43147112Sbostic 43247112Sbostic STATIC void 43347112Sbostic evalpipe(n) 43447112Sbostic union node *n; 43569391Schristos { 43647112Sbostic struct job *jp; 43747112Sbostic struct nodelist *lp; 43847112Sbostic int pipelen; 43947112Sbostic int prevfd; 44047112Sbostic int pip[2]; 44147112Sbostic 44269272Schristos TRACE(("evalpipe(0x%lx) called\n", (long)n)); 44347112Sbostic pipelen = 0; 44447112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 44547112Sbostic pipelen++; 44647112Sbostic INTOFF; 44747112Sbostic jp = makejob(n, pipelen); 44847112Sbostic prevfd = -1; 44947112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 45047112Sbostic prehash(lp->n); 45147112Sbostic pip[1] = -1; 45247112Sbostic if (lp->next) { 45347112Sbostic if (pipe(pip) < 0) { 45447112Sbostic close(prevfd); 45547112Sbostic error("Pipe call failed"); 45647112Sbostic } 45747112Sbostic } 45847112Sbostic if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 45947112Sbostic INTON; 46047112Sbostic if (prevfd > 0) { 46147112Sbostic close(0); 46247112Sbostic copyfd(prevfd, 0); 46347112Sbostic close(prevfd); 46447112Sbostic } 46547112Sbostic if (pip[1] >= 0) { 46647112Sbostic close(pip[0]); 46747112Sbostic if (pip[1] != 1) { 46847112Sbostic close(1); 46947112Sbostic copyfd(pip[1], 1); 47047112Sbostic close(pip[1]); 47147112Sbostic } 47247112Sbostic } 47347112Sbostic evaltree(lp->n, EV_EXIT); 47447112Sbostic } 47547112Sbostic if (prevfd >= 0) 47647112Sbostic close(prevfd); 47747112Sbostic prevfd = pip[0]; 47847112Sbostic close(pip[1]); 47947112Sbostic } 48047112Sbostic INTON; 48147112Sbostic if (n->npipe.backgnd == 0) { 48247112Sbostic INTOFF; 48347112Sbostic exitstatus = waitforjob(jp); 48447112Sbostic TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 48547112Sbostic INTON; 48647112Sbostic } 48747112Sbostic } 48847112Sbostic 48947112Sbostic 49047112Sbostic 49147112Sbostic /* 49247112Sbostic * Execute a command inside back quotes. If it's a builtin command, we 49347112Sbostic * want to save its output in a block obtained from malloc. Otherwise 49447112Sbostic * we fork off a subprocess and get the output of the command via a pipe. 49547112Sbostic * Should be called with interrupts off. 49647112Sbostic */ 49747112Sbostic 49847112Sbostic void 49947112Sbostic evalbackcmd(n, result) 50047112Sbostic union node *n; 50147112Sbostic struct backcmd *result; 50269391Schristos { 50347112Sbostic int pip[2]; 50447112Sbostic struct job *jp; 50547112Sbostic struct stackmark smark; /* unnecessary */ 50647112Sbostic 50747112Sbostic setstackmark(&smark); 50847112Sbostic result->fd = -1; 50947112Sbostic result->buf = NULL; 51047112Sbostic result->nleft = 0; 51147112Sbostic result->jp = NULL; 51255798Smarc exitstatus = 0; 51355798Smarc if (n == NULL) 51455798Smarc goto out; 51547112Sbostic if (n->type == NCMD) { 51647112Sbostic evalcommand(n, EV_BACKCMD, result); 51747112Sbostic } else { 51847112Sbostic if (pipe(pip) < 0) 51947112Sbostic error("Pipe call failed"); 52047112Sbostic jp = makejob(n, 1); 52147112Sbostic if (forkshell(jp, n, FORK_NOJOB) == 0) { 52247112Sbostic FORCEINTON; 52347112Sbostic close(pip[0]); 52447112Sbostic if (pip[1] != 1) { 52547112Sbostic close(1); 52647112Sbostic copyfd(pip[1], 1); 52747112Sbostic close(pip[1]); 52847112Sbostic } 52947112Sbostic evaltree(n, EV_EXIT); 53047112Sbostic } 53147112Sbostic close(pip[1]); 53247112Sbostic result->fd = pip[0]; 53347112Sbostic result->jp = jp; 53447112Sbostic } 53555798Smarc out: 53647112Sbostic popstackmark(&smark); 53747112Sbostic TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 53847112Sbostic result->fd, result->buf, result->nleft, result->jp)); 53947112Sbostic } 54047112Sbostic 54147112Sbostic 54247112Sbostic 54347112Sbostic /* 54447112Sbostic * Execute a simple command. 54547112Sbostic */ 54647112Sbostic 54747112Sbostic STATIC void 54847112Sbostic evalcommand(cmd, flags, backcmd) 54947112Sbostic union node *cmd; 55069272Schristos int flags; 55147112Sbostic struct backcmd *backcmd; 55269272Schristos { 55347112Sbostic struct stackmark smark; 55447112Sbostic union node *argp; 55547112Sbostic struct arglist arglist; 55647112Sbostic struct arglist varlist; 55747112Sbostic char **argv; 55847112Sbostic int argc; 55947112Sbostic char **envp; 56047112Sbostic int varflag; 56147112Sbostic struct strlist *sp; 56247112Sbostic int mode; 56347112Sbostic int pip[2]; 56447112Sbostic struct cmdentry cmdentry; 56547112Sbostic struct job *jp; 56647112Sbostic struct jmploc jmploc; 56747112Sbostic struct jmploc *volatile savehandler; 56847112Sbostic char *volatile savecmdname; 56947112Sbostic volatile struct shparam saveparam; 57047112Sbostic struct localvar *volatile savelocalvars; 57147112Sbostic volatile int e; 57247112Sbostic char *lastarg; 57369272Schristos #if __GNUC__ 57469272Schristos /* Avoid longjmp clobbering */ 57569272Schristos (void) &argv; 57669272Schristos (void) &argc; 57769272Schristos (void) &lastarg; 57869272Schristos (void) &flags; 57969272Schristos #endif 58047112Sbostic 58147112Sbostic /* First expand the arguments. */ 58269272Schristos TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 58347112Sbostic setstackmark(&smark); 58447112Sbostic arglist.lastp = &arglist.list; 58547112Sbostic varlist.lastp = &varlist.list; 58647112Sbostic varflag = 1; 58747112Sbostic for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 58869272Schristos char *p = argp->narg.text; 58947112Sbostic if (varflag && is_name(*p)) { 59047112Sbostic do { 59147112Sbostic p++; 59247112Sbostic } while (is_in_name(*p)); 59347112Sbostic if (*p == '=') { 59453298Smarc expandarg(argp, &varlist, EXP_VARTILDE); 59547112Sbostic continue; 59647112Sbostic } 59747112Sbostic } 59853298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 59947112Sbostic varflag = 0; 60047112Sbostic } 60147112Sbostic *arglist.lastp = NULL; 60247112Sbostic *varlist.lastp = NULL; 60347112Sbostic expredir(cmd->ncmd.redirect); 60447112Sbostic argc = 0; 60547112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) 60647112Sbostic argc++; 60747112Sbostic argv = stalloc(sizeof (char *) * (argc + 1)); 60855245Smarc 60953298Smarc for (sp = arglist.list ; sp ; sp = sp->next) { 61053298Smarc TRACE(("evalcommand arg: %s\n", sp->text)); 61147112Sbostic *argv++ = sp->text; 61253298Smarc } 61347112Sbostic *argv = NULL; 61447112Sbostic lastarg = NULL; 61547112Sbostic if (iflag && funcnest == 0 && argc > 0) 61647112Sbostic lastarg = argv[-1]; 61747112Sbostic argv -= argc; 61847112Sbostic 61947112Sbostic /* Print the command if xflag is set. */ 62047112Sbostic if (xflag) { 62147112Sbostic outc('+', &errout); 62247112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) { 62347112Sbostic outc(' ', &errout); 62447112Sbostic out2str(sp->text); 62547112Sbostic } 62647112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 62747112Sbostic outc(' ', &errout); 62847112Sbostic out2str(sp->text); 62947112Sbostic } 63047112Sbostic outc('\n', &errout); 63147112Sbostic flushout(&errout); 63247112Sbostic } 63347112Sbostic 63447112Sbostic /* Now locate the command. */ 63547112Sbostic if (argc == 0) { 63647112Sbostic cmdentry.cmdtype = CMDBUILTIN; 63747112Sbostic cmdentry.u.index = BLTINCMD; 63847112Sbostic } else { 63947112Sbostic find_command(argv[0], &cmdentry, 1); 64047112Sbostic if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 64147112Sbostic exitstatus = 2; 64247112Sbostic flushout(&errout); 64347112Sbostic return; 64447112Sbostic } 64547112Sbostic /* implement the bltin builtin here */ 64647112Sbostic if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 64747112Sbostic for (;;) { 64847112Sbostic argv++; 64947112Sbostic if (--argc == 0) 65047112Sbostic break; 65147112Sbostic if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 65247112Sbostic outfmt(&errout, "%s: not found\n", *argv); 65347112Sbostic exitstatus = 2; 65447112Sbostic flushout(&errout); 65547112Sbostic return; 65647112Sbostic } 65747112Sbostic if (cmdentry.u.index != BLTINCMD) 65847112Sbostic break; 65947112Sbostic } 66047112Sbostic } 66147112Sbostic } 66247112Sbostic 66347112Sbostic /* Fork off a child process if necessary. */ 66447112Sbostic if (cmd->ncmd.backgnd 66569272Schristos || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) 66669272Schristos || ((flags & EV_BACKCMD) != 0 66747112Sbostic && (cmdentry.cmdtype != CMDBUILTIN 66847112Sbostic || cmdentry.u.index == DOTCMD 66969272Schristos || cmdentry.u.index == EVALCMD))) { 67047112Sbostic jp = makejob(cmd, 1); 67147112Sbostic mode = cmd->ncmd.backgnd; 67247112Sbostic if (flags & EV_BACKCMD) { 67347112Sbostic mode = FORK_NOJOB; 67447112Sbostic if (pipe(pip) < 0) 67547112Sbostic error("Pipe call failed"); 67647112Sbostic } 67747112Sbostic if (forkshell(jp, cmd, mode) != 0) 67847112Sbostic goto parent; /* at end of routine */ 67947112Sbostic if (flags & EV_BACKCMD) { 68047112Sbostic FORCEINTON; 68147112Sbostic close(pip[0]); 68247112Sbostic if (pip[1] != 1) { 68347112Sbostic close(1); 68447112Sbostic copyfd(pip[1], 1); 68547112Sbostic close(pip[1]); 68647112Sbostic } 68747112Sbostic } 68847112Sbostic flags |= EV_EXIT; 68947112Sbostic } 69047112Sbostic 69147112Sbostic /* This is the child process if a fork occurred. */ 69247112Sbostic /* Execute the command. */ 69347112Sbostic if (cmdentry.cmdtype == CMDFUNCTION) { 69447112Sbostic trputs("Shell function: "); trargs(argv); 69547112Sbostic redirect(cmd->ncmd.redirect, REDIR_PUSH); 69647112Sbostic saveparam = shellparam; 69747112Sbostic shellparam.malloc = 0; 69847112Sbostic shellparam.nparam = argc - 1; 69947112Sbostic shellparam.p = argv + 1; 70047112Sbostic shellparam.optnext = NULL; 70147112Sbostic INTOFF; 70247112Sbostic savelocalvars = localvars; 70347112Sbostic localvars = NULL; 70447112Sbostic INTON; 70547112Sbostic if (setjmp(jmploc.loc)) { 70647112Sbostic if (exception == EXSHELLPROC) 70747112Sbostic freeparam((struct shparam *)&saveparam); 70847112Sbostic else { 70947112Sbostic freeparam(&shellparam); 71047112Sbostic shellparam = saveparam; 71147112Sbostic } 71247112Sbostic poplocalvars(); 71347112Sbostic localvars = savelocalvars; 71447112Sbostic handler = savehandler; 71547112Sbostic longjmp(handler->loc, 1); 71647112Sbostic } 71747112Sbostic savehandler = handler; 71847112Sbostic handler = &jmploc; 71947112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 72047112Sbostic mklocal(sp->text); 72147112Sbostic funcnest++; 72247112Sbostic evaltree(cmdentry.u.func, 0); 72347112Sbostic funcnest--; 72447112Sbostic INTOFF; 72547112Sbostic poplocalvars(); 72647112Sbostic localvars = savelocalvars; 72747112Sbostic freeparam(&shellparam); 72847112Sbostic shellparam = saveparam; 72947112Sbostic handler = savehandler; 73047112Sbostic popredir(); 73147112Sbostic INTON; 73247112Sbostic if (evalskip == SKIPFUNC) { 73347112Sbostic evalskip = 0; 73447112Sbostic skipcount = 0; 73547112Sbostic } 73647112Sbostic if (flags & EV_EXIT) 73747112Sbostic exitshell(exitstatus); 73847112Sbostic } else if (cmdentry.cmdtype == CMDBUILTIN) { 73947112Sbostic trputs("builtin command: "); trargs(argv); 74047112Sbostic mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 74147112Sbostic if (flags == EV_BACKCMD) { 74247112Sbostic memout.nleft = 0; 74347112Sbostic memout.nextc = memout.buf; 74447112Sbostic memout.bufsize = 64; 74547112Sbostic mode |= REDIR_BACKQ; 74647112Sbostic } 74747112Sbostic redirect(cmd->ncmd.redirect, mode); 74847112Sbostic savecmdname = commandname; 74947112Sbostic cmdenviron = varlist.list; 75047112Sbostic e = -1; 75147112Sbostic if (setjmp(jmploc.loc)) { 75247112Sbostic e = exception; 75347112Sbostic exitstatus = (e == EXINT)? SIGINT+128 : 2; 75447112Sbostic goto cmddone; 75547112Sbostic } 75647112Sbostic savehandler = handler; 75747112Sbostic handler = &jmploc; 75847112Sbostic commandname = argv[0]; 75947112Sbostic argptr = argv + 1; 76047112Sbostic optptr = NULL; /* initialize nextopt */ 76147112Sbostic exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 76247112Sbostic flushall(); 76347112Sbostic cmddone: 76447112Sbostic out1 = &output; 76547112Sbostic out2 = &errout; 76647112Sbostic freestdout(); 76747112Sbostic if (e != EXSHELLPROC) { 76847112Sbostic commandname = savecmdname; 76947112Sbostic if (flags & EV_EXIT) { 77047112Sbostic exitshell(exitstatus); 77147112Sbostic } 77247112Sbostic } 77347112Sbostic handler = savehandler; 77447112Sbostic if (e != -1) { 77547112Sbostic if (e != EXERROR || cmdentry.u.index == BLTINCMD 77647112Sbostic || cmdentry.u.index == DOTCMD 77747112Sbostic || cmdentry.u.index == EVALCMD 77869272Schristos #ifndef NO_HISTORY 77955245Smarc || cmdentry.u.index == HISTCMD 78069272Schristos #endif 78147112Sbostic || cmdentry.u.index == EXECCMD) 78247112Sbostic exraise(e); 78347112Sbostic FORCEINTON; 78447112Sbostic } 78547112Sbostic if (cmdentry.u.index != EXECCMD) 78647112Sbostic popredir(); 78747112Sbostic if (flags == EV_BACKCMD) { 78847112Sbostic backcmd->buf = memout.buf; 78947112Sbostic backcmd->nleft = memout.nextc - memout.buf; 79047112Sbostic memout.buf = NULL; 79147112Sbostic } 79247112Sbostic } else { 79347112Sbostic trputs("normal command: "); trargs(argv); 79447112Sbostic clearredir(); 79547112Sbostic redirect(cmd->ncmd.redirect, 0); 79647112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 79747112Sbostic setvareq(sp->text, VEXPORT|VSTACK); 79847112Sbostic envp = environment(); 79969272Schristos shellexec(argv, envp, pathval(), cmdentry.u.index); 80047112Sbostic /*NOTREACHED*/ 80147112Sbostic } 80247112Sbostic goto out; 80347112Sbostic 80447112Sbostic parent: /* parent process gets here (if we forked) */ 80547112Sbostic if (mode == 0) { /* argument to fork */ 80647112Sbostic INTOFF; 80747112Sbostic exitstatus = waitforjob(jp); 80847112Sbostic INTON; 80947112Sbostic } else if (mode == 2) { 81047112Sbostic backcmd->fd = pip[0]; 81147112Sbostic close(pip[1]); 81247112Sbostic backcmd->jp = jp; 81347112Sbostic } 81447112Sbostic 81547112Sbostic out: 81647112Sbostic if (lastarg) 81747112Sbostic setvar("_", lastarg, 0); 81847112Sbostic popstackmark(&smark); 81947112Sbostic } 82047112Sbostic 82147112Sbostic 82247112Sbostic 82347112Sbostic /* 82447112Sbostic * Search for a command. This is called before we fork so that the 82547112Sbostic * location of the command will be available in the parent as well as 82647112Sbostic * the child. The check for "goodname" is an overly conservative 82747112Sbostic * check that the name will not be subject to expansion. 82847112Sbostic */ 82947112Sbostic 83047112Sbostic STATIC void 83147112Sbostic prehash(n) 83247112Sbostic union node *n; 83369391Schristos { 83447112Sbostic struct cmdentry entry; 83547112Sbostic 83669272Schristos if (n->type == NCMD && n->ncmd.args) 83769272Schristos if (goodname(n->ncmd.args->narg.text)) 83869272Schristos find_command(n->ncmd.args->narg.text, &entry, 0); 83947112Sbostic } 84047112Sbostic 84147112Sbostic 84247112Sbostic 84347112Sbostic /* 84447112Sbostic * Builtin commands. Builtin commands whose functions are closely 84547112Sbostic * tied to evaluation are implemented here. 84647112Sbostic */ 84747112Sbostic 84847112Sbostic /* 84947112Sbostic * No command given, or a bltin command with no arguments. Set the 85047112Sbostic * specified variables. 85147112Sbostic */ 85247112Sbostic 85369272Schristos int 85469272Schristos bltincmd(argc, argv) 85569272Schristos int argc; 85669272Schristos char **argv; 85769272Schristos { 85847112Sbostic listsetvar(cmdenviron); 85969391Schristos /* 86069391Schristos * Preserve exitstatus of a previous possible redirection 86169391Schristos * as POSIX mandates 86269391Schristos */ 86369391Schristos return exitstatus; 86447112Sbostic } 86547112Sbostic 86647112Sbostic 86747112Sbostic /* 86847112Sbostic * Handle break and continue commands. Break, continue, and return are 86947112Sbostic * all handled by setting the evalskip flag. The evaluation routines 87047112Sbostic * above all check this flag, and if it is set they start skipping 87147112Sbostic * commands rather than executing them. The variable skipcount is 87247112Sbostic * the number of loops to break/continue, or the number of function 87347112Sbostic * levels to return. (The latter is always 1.) It should probably 87447112Sbostic * be an error to break out of more loops than exist, but it isn't 87547112Sbostic * in the standard shell so we don't make it one here. 87647112Sbostic */ 87747112Sbostic 87869272Schristos int 87969272Schristos breakcmd(argc, argv) 88069272Schristos int argc; 88169272Schristos char **argv; 88269272Schristos { 88347112Sbostic int n; 88447112Sbostic 88547112Sbostic n = 1; 88647112Sbostic if (argc > 1) 88747112Sbostic n = number(argv[1]); 88847112Sbostic if (n > loopnest) 88947112Sbostic n = loopnest; 89047112Sbostic if (n > 0) { 89147112Sbostic evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 89247112Sbostic skipcount = n; 89347112Sbostic } 89447112Sbostic return 0; 89547112Sbostic } 89647112Sbostic 89747112Sbostic 89847112Sbostic /* 89947112Sbostic * The return command. 90047112Sbostic */ 90147112Sbostic 90269272Schristos int 90369272Schristos returncmd(argc, argv) 90469272Schristos int argc; 90569272Schristos char **argv; 90669272Schristos { 90747112Sbostic int ret; 90847112Sbostic 90947112Sbostic ret = exitstatus; 91047112Sbostic if (argc > 1) 91147112Sbostic ret = number(argv[1]); 91247112Sbostic if (funcnest) { 91347112Sbostic evalskip = SKIPFUNC; 91447112Sbostic skipcount = 1; 91547112Sbostic } 91647112Sbostic return ret; 91747112Sbostic } 91847112Sbostic 91947112Sbostic 92069272Schristos int 92169272Schristos falsecmd(argc, argv) 92269272Schristos int argc; 92369272Schristos char **argv; 92469272Schristos { 92568916Sbostic return 1; 92668916Sbostic } 92768916Sbostic 92868916Sbostic 92969272Schristos int 93069272Schristos truecmd(argc, argv) 93169272Schristos int argc; 93269272Schristos char **argv; 93369272Schristos { 93447112Sbostic return 0; 93547112Sbostic } 93647112Sbostic 93747112Sbostic 93869272Schristos int 93969272Schristos execcmd(argc, argv) 94069272Schristos int argc; 94169272Schristos char **argv; 94269272Schristos { 94347112Sbostic if (argc > 1) { 94469272Schristos struct strlist *sp; 94569272Schristos 94647112Sbostic iflag = 0; /* exit on error */ 94755245Smarc mflag = 0; 94855245Smarc optschanged(); 94969272Schristos for (sp = cmdenviron; sp ; sp = sp->next) 95069272Schristos setvareq(sp->text, VEXPORT|VSTACK); 95147112Sbostic shellexec(argv + 1, environment(), pathval(), 0); 95247112Sbostic 95347112Sbostic } 95447112Sbostic return 0; 95547112Sbostic } 956