147112Sbostic /*- 247112Sbostic * Copyright (c) 1991 The Regents of the University of California. 347112Sbostic * All rights reserved. 447112Sbostic * 547112Sbostic * This code is derived from software contributed to Berkeley by 647112Sbostic * Kenneth Almquist. 747112Sbostic * 853298Smarc * Redistribution and use in source and binary forms, with or without 953298Smarc * modification, are permitted provided that the following conditions 1053298Smarc * are met: 1153298Smarc * 1. Redistributions of source code must retain the above copyright 1253298Smarc * notice, this list of conditions and the following disclaimer. 1353298Smarc * 2. Redistributions in binary form must reproduce the above copyright 1453298Smarc * notice, this list of conditions and the following disclaimer in the 1553298Smarc * documentation and/or other materials provided with the distribution. 1653298Smarc * 3. All advertising materials mentioning features or use of this software 1753298Smarc * must display the following acknowledgement: 1853298Smarc * This product includes software developed by the University of 1953298Smarc * California, Berkeley and its contributors. 2053298Smarc * 4. Neither the name of the University nor the names of its contributors 2153298Smarc * may be used to endorse or promote products derived from this software 2253298Smarc * without specific prior written permission. 2353298Smarc * 2453298Smarc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2553298Smarc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2653298Smarc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2753298Smarc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2853298Smarc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2953298Smarc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3053298Smarc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3153298Smarc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3253298Smarc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3353298Smarc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3453298Smarc * SUCH DAMAGE. 3547112Sbostic */ 3647112Sbostic 3747112Sbostic #ifndef lint 3853298Smarc static char sccsid[] = "@(#)eval.c 5.4 (Berkeley) 4/16/92"; 3947112Sbostic #endif /* not lint */ 4047112Sbostic 4147112Sbostic /* 4247112Sbostic * Evaluate a command. 4347112Sbostic */ 4447112Sbostic 4547112Sbostic #include "shell.h" 4647112Sbostic #include "nodes.h" 4747112Sbostic #include "syntax.h" 4847112Sbostic #include "expand.h" 4947112Sbostic #include "parser.h" 5047112Sbostic #include "jobs.h" 5147112Sbostic #include "eval.h" 5247112Sbostic #include "builtins.h" 5347112Sbostic #include "options.h" 5447112Sbostic #include "exec.h" 5547112Sbostic #include "redir.h" 5647112Sbostic #include "input.h" 5747112Sbostic #include "output.h" 5847112Sbostic #include "trap.h" 5947112Sbostic #include "var.h" 6047112Sbostic #include "memalloc.h" 6147112Sbostic #include "error.h" 6247112Sbostic #include "mystring.h" 63*55245Smarc #include "myhistedit.h" 6447112Sbostic #include <signal.h> 6547112Sbostic 6647112Sbostic 6747112Sbostic /* flags in argument to evaltree */ 6847112Sbostic #define EV_EXIT 01 /* exit after evaluating tree */ 6947112Sbostic #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 7047112Sbostic #define EV_BACKCMD 04 /* command executing within back quotes */ 7147112Sbostic 7247112Sbostic 7347112Sbostic /* reasons for skipping commands (see comment on breakcmd routine) */ 7447112Sbostic #define SKIPBREAK 1 7547112Sbostic #define SKIPCONT 2 7647112Sbostic #define SKIPFUNC 3 7747112Sbostic 7847112Sbostic MKINIT int evalskip; /* set if we are skipping commands */ 7947112Sbostic STATIC int skipcount; /* number of levels to skip */ 8047112Sbostic MKINIT int loopnest; /* current loop nesting level */ 8147112Sbostic int funcnest; /* depth of function calls */ 8247112Sbostic 8347112Sbostic 8447112Sbostic char *commandname; 8547112Sbostic struct strlist *cmdenviron; 8647112Sbostic int exitstatus; /* exit status of last command */ 8747112Sbostic 8847112Sbostic 8947112Sbostic #ifdef __STDC__ 9047112Sbostic STATIC void evalloop(union node *); 9147112Sbostic STATIC void evalfor(union node *); 9247112Sbostic STATIC void evalcase(union node *, int); 9347112Sbostic STATIC void evalsubshell(union node *, int); 9447112Sbostic STATIC void expredir(union node *); 9547112Sbostic STATIC void evalpipe(union node *); 9647112Sbostic STATIC void evalcommand(union node *, int, struct backcmd *); 9747112Sbostic STATIC void prehash(union node *); 9847112Sbostic #else 9947112Sbostic STATIC void evalloop(); 10047112Sbostic STATIC void evalfor(); 10147112Sbostic STATIC void evalcase(); 10247112Sbostic STATIC void evalsubshell(); 10347112Sbostic STATIC void expredir(); 10447112Sbostic STATIC void evalpipe(); 10547112Sbostic STATIC void evalcommand(); 10647112Sbostic STATIC void prehash(); 10747112Sbostic #endif 10847112Sbostic 10947112Sbostic 11047112Sbostic 11147112Sbostic /* 11247112Sbostic * Called to reset things after an exception. 11347112Sbostic */ 11447112Sbostic 11547112Sbostic #ifdef mkinit 11647112Sbostic INCLUDE "eval.h" 11747112Sbostic 11847112Sbostic RESET { 11947112Sbostic evalskip = 0; 12047112Sbostic loopnest = 0; 12147112Sbostic funcnest = 0; 12247112Sbostic } 12347112Sbostic 12447112Sbostic SHELLPROC { 12547112Sbostic exitstatus = 0; 12647112Sbostic } 12747112Sbostic #endif 12847112Sbostic 12947112Sbostic 13047112Sbostic 13147112Sbostic /* 13247292Smarc * The eval commmand. 13347112Sbostic */ 13447112Sbostic 13547292Smarc evalcmd(argc, argv) 13647292Smarc char **argv; 13747292Smarc { 13847292Smarc char *p; 13947292Smarc char *concat; 14047292Smarc char **ap; 14147112Sbostic 14247292Smarc if (argc > 1) { 14347292Smarc p = argv[1]; 14447292Smarc if (argc > 2) { 14547292Smarc STARTSTACKSTR(concat); 14647292Smarc ap = argv + 2; 14747292Smarc for (;;) { 14847292Smarc while (*p) 14947292Smarc STPUTC(*p++, concat); 15047292Smarc if ((p = *ap++) == NULL) 15147292Smarc break; 15247292Smarc STPUTC(' ', concat); 15347292Smarc } 15447292Smarc STPUTC('\0', concat); 15547292Smarc p = grabstackstr(concat); 15647292Smarc } 15747292Smarc evalstring(p); 15847292Smarc } 15947292Smarc return exitstatus; 16047112Sbostic } 16147112Sbostic 16247112Sbostic 16347112Sbostic /* 16447112Sbostic * Execute a command or commands contained in a string. 16547112Sbostic */ 16647112Sbostic 16747112Sbostic void 16847112Sbostic evalstring(s) 16947112Sbostic char *s; 17047112Sbostic { 17147112Sbostic union node *n; 17247112Sbostic struct stackmark smark; 17347112Sbostic 17447112Sbostic setstackmark(&smark); 17547112Sbostic setinputstring(s, 1); 17647112Sbostic while ((n = parsecmd(0)) != NEOF) { 17747112Sbostic evaltree(n, 0); 17847112Sbostic popstackmark(&smark); 17947112Sbostic } 18047112Sbostic popfile(); 18147112Sbostic popstackmark(&smark); 18247112Sbostic } 18347112Sbostic 18447112Sbostic 18547112Sbostic 18647112Sbostic /* 18747112Sbostic * Evaluate a parse tree. The value is left in the global variable 18847112Sbostic * exitstatus. 18947112Sbostic */ 19047112Sbostic 19147112Sbostic void 19247112Sbostic evaltree(n, flags) 19347112Sbostic union node *n; 19447112Sbostic { 19547112Sbostic if (n == NULL) { 19647112Sbostic TRACE(("evaltree(NULL) called\n")); 197*55245Smarc exitstatus = 0; 198*55245Smarc goto out; 19947112Sbostic } 200*55245Smarc displayhist = 1; /* show history substitutions done with fc */ 20147112Sbostic TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type)); 20247112Sbostic switch (n->type) { 20347112Sbostic case NSEMI: 20447112Sbostic evaltree(n->nbinary.ch1, 0); 20547112Sbostic if (evalskip) 20647112Sbostic goto out; 20747112Sbostic evaltree(n->nbinary.ch2, flags); 20847112Sbostic break; 20947112Sbostic case NAND: 21047112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 21147112Sbostic if (evalskip || exitstatus != 0) 21247112Sbostic goto out; 21347112Sbostic evaltree(n->nbinary.ch2, flags); 21447112Sbostic break; 21547112Sbostic case NOR: 21647112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 21747112Sbostic if (evalskip || exitstatus == 0) 21847112Sbostic goto out; 21947112Sbostic evaltree(n->nbinary.ch2, flags); 22047112Sbostic break; 22147112Sbostic case NREDIR: 22247112Sbostic expredir(n->nredir.redirect); 22347112Sbostic redirect(n->nredir.redirect, REDIR_PUSH); 22447112Sbostic evaltree(n->nredir.n, flags); 22547112Sbostic popredir(); 22647112Sbostic break; 22747112Sbostic case NSUBSHELL: 22847112Sbostic evalsubshell(n, flags); 22947112Sbostic break; 23047112Sbostic case NBACKGND: 23147112Sbostic evalsubshell(n, flags); 23247112Sbostic break; 23347982Smarc case NIF: { 23447982Smarc int status = 0; 23547982Smarc 23647112Sbostic evaltree(n->nif.test, EV_TESTED); 23747112Sbostic if (evalskip) 23847112Sbostic goto out; 23947112Sbostic if (exitstatus == 0) { 24047112Sbostic evaltree(n->nif.ifpart, flags); 24147982Smarc status = exitstatus; 24247112Sbostic } else if (n->nif.elsepart) { 24347112Sbostic evaltree(n->nif.elsepart, flags); 24447982Smarc status = exitstatus; 24547112Sbostic } 24647982Smarc exitstatus = status; 24747112Sbostic break; 24847982Smarc } 24947112Sbostic case NWHILE: 25047112Sbostic case NUNTIL: 25147112Sbostic evalloop(n); 25247112Sbostic break; 25347112Sbostic case NFOR: 25447112Sbostic evalfor(n); 25547112Sbostic break; 25647112Sbostic case NCASE: 25747112Sbostic evalcase(n, flags); 25847112Sbostic break; 25947112Sbostic case NDEFUN: 26047112Sbostic defun(n->narg.text, n->narg.next); 26147112Sbostic exitstatus = 0; 26247112Sbostic break; 26353175Smarc case NNOT: 26453175Smarc evaltree(n->nnot.com, EV_TESTED); 26553175Smarc exitstatus = !exitstatus; 26653175Smarc break; 26753175Smarc 26847112Sbostic case NPIPE: 26947112Sbostic evalpipe(n); 27047112Sbostic break; 27147112Sbostic case NCMD: 27247112Sbostic evalcommand(n, flags, (struct backcmd *)NULL); 27347112Sbostic break; 27447112Sbostic default: 27547112Sbostic out1fmt("Node type = %d\n", n->type); 27647112Sbostic flushout(&output); 27747112Sbostic break; 27847112Sbostic } 27947112Sbostic out: 28047112Sbostic if (pendingsigs) 28147112Sbostic dotrap(); 28247112Sbostic if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 28347112Sbostic exitshell(exitstatus); 28447112Sbostic } 28547112Sbostic 28647112Sbostic 28747112Sbostic STATIC void 28847112Sbostic evalloop(n) 28947112Sbostic union node *n; 29047112Sbostic { 29147112Sbostic int status; 29247112Sbostic 29347112Sbostic loopnest++; 29447112Sbostic status = 0; 29547112Sbostic for (;;) { 29647112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 29747112Sbostic if (evalskip) { 29847112Sbostic skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 29947112Sbostic evalskip = 0; 30047112Sbostic continue; 30147112Sbostic } 30247112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 30347112Sbostic evalskip = 0; 30447112Sbostic break; 30547112Sbostic } 30647112Sbostic if (n->type == NWHILE) { 30747112Sbostic if (exitstatus != 0) 30847112Sbostic break; 30947112Sbostic } else { 31047112Sbostic if (exitstatus == 0) 31147112Sbostic break; 31247112Sbostic } 31347112Sbostic evaltree(n->nbinary.ch2, 0); 31447112Sbostic status = exitstatus; 31547112Sbostic if (evalskip) 31647112Sbostic goto skipping; 31747112Sbostic } 31847112Sbostic loopnest--; 31947112Sbostic exitstatus = status; 32047112Sbostic } 32147112Sbostic 32247112Sbostic 32347112Sbostic 32447112Sbostic STATIC void 32547112Sbostic evalfor(n) 32647112Sbostic union node *n; 32747112Sbostic { 32847112Sbostic struct arglist arglist; 32947112Sbostic union node *argp; 33047112Sbostic struct strlist *sp; 33147112Sbostic struct stackmark smark; 33247112Sbostic 33347112Sbostic setstackmark(&smark); 33447112Sbostic arglist.lastp = &arglist.list; 33547112Sbostic for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 33653298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 33747112Sbostic if (evalskip) 33847112Sbostic goto out; 33947112Sbostic } 34047112Sbostic *arglist.lastp = NULL; 34147112Sbostic 34247112Sbostic exitstatus = 0; 34347112Sbostic loopnest++; 34447112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 34547112Sbostic setvar(n->nfor.var, sp->text, 0); 34647112Sbostic evaltree(n->nfor.body, 0); 34747112Sbostic if (evalskip) { 34847112Sbostic if (evalskip == SKIPCONT && --skipcount <= 0) { 34947112Sbostic evalskip = 0; 35047112Sbostic continue; 35147112Sbostic } 35247112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 35347112Sbostic evalskip = 0; 35447112Sbostic break; 35547112Sbostic } 35647112Sbostic } 35747112Sbostic loopnest--; 35847112Sbostic out: 35947112Sbostic popstackmark(&smark); 36047112Sbostic } 36147112Sbostic 36247112Sbostic 36347112Sbostic 36447112Sbostic STATIC void 36547112Sbostic evalcase(n, flags) 36647112Sbostic union node *n; 36747112Sbostic { 36847112Sbostic union node *cp; 36947112Sbostic union node *patp; 37047112Sbostic struct arglist arglist; 37147112Sbostic struct stackmark smark; 37247112Sbostic 37347112Sbostic setstackmark(&smark); 37447112Sbostic arglist.lastp = &arglist.list; 37553298Smarc expandarg(n->ncase.expr, &arglist, EXP_TILDE); 37647112Sbostic for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 37747112Sbostic for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 37847112Sbostic if (casematch(patp, arglist.list->text)) { 37947112Sbostic if (evalskip == 0) { 38047112Sbostic evaltree(cp->nclist.body, flags); 38147112Sbostic } 38247112Sbostic goto out; 38347112Sbostic } 38447112Sbostic } 38547112Sbostic } 38647112Sbostic out: 38747112Sbostic popstackmark(&smark); 38847112Sbostic } 38947112Sbostic 39047112Sbostic 39147112Sbostic 39247112Sbostic /* 39347112Sbostic * Kick off a subshell to evaluate a tree. 39447112Sbostic */ 39547112Sbostic 39647112Sbostic STATIC void 39747112Sbostic evalsubshell(n, flags) 39847112Sbostic union node *n; 39947112Sbostic { 40047112Sbostic struct job *jp; 40147112Sbostic int backgnd = (n->type == NBACKGND); 40247112Sbostic 40347112Sbostic expredir(n->nredir.redirect); 40447112Sbostic jp = makejob(n, 1); 40547112Sbostic if (forkshell(jp, n, backgnd) == 0) { 40647112Sbostic if (backgnd) 40747112Sbostic flags &=~ EV_TESTED; 40847112Sbostic redirect(n->nredir.redirect, 0); 40947112Sbostic evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 41047112Sbostic } 41147112Sbostic if (! backgnd) { 41247112Sbostic INTOFF; 41347112Sbostic exitstatus = waitforjob(jp); 41447112Sbostic INTON; 41547112Sbostic } 41647112Sbostic } 41747112Sbostic 41847112Sbostic 41947112Sbostic 42047112Sbostic /* 42147112Sbostic * Compute the names of the files in a redirection list. 42247112Sbostic */ 42347112Sbostic 42447112Sbostic STATIC void 42547112Sbostic expredir(n) 42647112Sbostic union node *n; 42747112Sbostic { 42847112Sbostic register union node *redir; 42947112Sbostic 43047112Sbostic for (redir = n ; redir ; redir = redir->nfile.next) { 43147112Sbostic if (redir->type == NFROM 43247112Sbostic || redir->type == NTO 43347112Sbostic || redir->type == NAPPEND) { 43447112Sbostic struct arglist fn; 43547112Sbostic fn.lastp = &fn.list; 43653298Smarc expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 43747112Sbostic redir->nfile.expfname = fn.list->text; 43847112Sbostic } 43947112Sbostic } 44047112Sbostic } 44147112Sbostic 44247112Sbostic 44347112Sbostic 44447112Sbostic /* 44547112Sbostic * Evaluate a pipeline. All the processes in the pipeline are children 44647112Sbostic * of the process creating the pipeline. (This differs from some versions 44747112Sbostic * of the shell, which make the last process in a pipeline the parent 44847112Sbostic * of all the rest.) 44947112Sbostic */ 45047112Sbostic 45147112Sbostic STATIC void 45247112Sbostic evalpipe(n) 45347112Sbostic union node *n; 45447112Sbostic { 45547112Sbostic struct job *jp; 45647112Sbostic struct nodelist *lp; 45747112Sbostic int pipelen; 45847112Sbostic int prevfd; 45947112Sbostic int pip[2]; 46047112Sbostic 46147112Sbostic TRACE(("evalpipe(0x%x) called\n", (int)n)); 46247112Sbostic pipelen = 0; 46347112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 46447112Sbostic pipelen++; 46547112Sbostic INTOFF; 46647112Sbostic jp = makejob(n, pipelen); 46747112Sbostic prevfd = -1; 46847112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 46947112Sbostic prehash(lp->n); 47047112Sbostic pip[1] = -1; 47147112Sbostic if (lp->next) { 47247112Sbostic if (pipe(pip) < 0) { 47347112Sbostic close(prevfd); 47447112Sbostic error("Pipe call failed"); 47547112Sbostic } 47647112Sbostic } 47747112Sbostic if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 47847112Sbostic INTON; 47947112Sbostic if (prevfd > 0) { 48047112Sbostic close(0); 48147112Sbostic copyfd(prevfd, 0); 48247112Sbostic close(prevfd); 48347112Sbostic } 48447112Sbostic if (pip[1] >= 0) { 48547112Sbostic close(pip[0]); 48647112Sbostic if (pip[1] != 1) { 48747112Sbostic close(1); 48847112Sbostic copyfd(pip[1], 1); 48947112Sbostic close(pip[1]); 49047112Sbostic } 49147112Sbostic } 49247112Sbostic evaltree(lp->n, EV_EXIT); 49347112Sbostic } 49447112Sbostic if (prevfd >= 0) 49547112Sbostic close(prevfd); 49647112Sbostic prevfd = pip[0]; 49747112Sbostic close(pip[1]); 49847112Sbostic } 49947112Sbostic INTON; 50047112Sbostic if (n->npipe.backgnd == 0) { 50147112Sbostic INTOFF; 50247112Sbostic exitstatus = waitforjob(jp); 50347112Sbostic TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 50447112Sbostic INTON; 50547112Sbostic } 50647112Sbostic } 50747112Sbostic 50847112Sbostic 50947112Sbostic 51047112Sbostic /* 51147112Sbostic * Execute a command inside back quotes. If it's a builtin command, we 51247112Sbostic * want to save its output in a block obtained from malloc. Otherwise 51347112Sbostic * we fork off a subprocess and get the output of the command via a pipe. 51447112Sbostic * Should be called with interrupts off. 51547112Sbostic */ 51647112Sbostic 51747112Sbostic void 51847112Sbostic evalbackcmd(n, result) 51947112Sbostic union node *n; 52047112Sbostic struct backcmd *result; 52147112Sbostic { 52247112Sbostic int pip[2]; 52347112Sbostic struct job *jp; 52447112Sbostic struct stackmark smark; /* unnecessary */ 52547112Sbostic 52647112Sbostic setstackmark(&smark); 52747112Sbostic result->fd = -1; 52847112Sbostic result->buf = NULL; 52947112Sbostic result->nleft = 0; 53047112Sbostic result->jp = NULL; 53147112Sbostic if (n->type == NCMD) { 53247112Sbostic evalcommand(n, EV_BACKCMD, result); 53347112Sbostic } else { 53447112Sbostic if (pipe(pip) < 0) 53547112Sbostic error("Pipe call failed"); 53647112Sbostic jp = makejob(n, 1); 53747112Sbostic if (forkshell(jp, n, FORK_NOJOB) == 0) { 53847112Sbostic FORCEINTON; 53947112Sbostic close(pip[0]); 54047112Sbostic if (pip[1] != 1) { 54147112Sbostic close(1); 54247112Sbostic copyfd(pip[1], 1); 54347112Sbostic close(pip[1]); 54447112Sbostic } 54547112Sbostic evaltree(n, EV_EXIT); 54647112Sbostic } 54747112Sbostic close(pip[1]); 54847112Sbostic result->fd = pip[0]; 54947112Sbostic result->jp = jp; 55047112Sbostic } 55147112Sbostic popstackmark(&smark); 55247112Sbostic TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 55347112Sbostic result->fd, result->buf, result->nleft, result->jp)); 55447112Sbostic } 55547112Sbostic 55647112Sbostic 55747112Sbostic 55847112Sbostic /* 55947112Sbostic * Execute a simple command. 56047112Sbostic */ 56147112Sbostic 56247112Sbostic STATIC void 56347112Sbostic evalcommand(cmd, flags, backcmd) 56447112Sbostic union node *cmd; 56547112Sbostic struct backcmd *backcmd; 56647112Sbostic { 56747112Sbostic struct stackmark smark; 56847112Sbostic union node *argp; 56947112Sbostic struct arglist arglist; 57047112Sbostic struct arglist varlist; 57147112Sbostic char **argv; 57247112Sbostic int argc; 57347112Sbostic char **envp; 57447112Sbostic int varflag; 57547112Sbostic struct strlist *sp; 57647112Sbostic register char *p; 57747112Sbostic int mode; 57847112Sbostic int pip[2]; 57947112Sbostic struct cmdentry cmdentry; 58047112Sbostic struct job *jp; 58147112Sbostic struct jmploc jmploc; 58247112Sbostic struct jmploc *volatile savehandler; 58347112Sbostic char *volatile savecmdname; 58447112Sbostic volatile struct shparam saveparam; 58547112Sbostic struct localvar *volatile savelocalvars; 58647112Sbostic volatile int e; 58747112Sbostic char *lastarg; 58847112Sbostic 58947112Sbostic /* First expand the arguments. */ 59047112Sbostic TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags)); 59147112Sbostic setstackmark(&smark); 59247112Sbostic arglist.lastp = &arglist.list; 59347112Sbostic varlist.lastp = &varlist.list; 59447112Sbostic varflag = 1; 59547112Sbostic for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 59647112Sbostic p = argp->narg.text; 59747112Sbostic if (varflag && is_name(*p)) { 59847112Sbostic do { 59947112Sbostic p++; 60047112Sbostic } while (is_in_name(*p)); 60147112Sbostic if (*p == '=') { 60253298Smarc expandarg(argp, &varlist, EXP_VARTILDE); 60347112Sbostic continue; 60447112Sbostic } 60547112Sbostic } 60653298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 60747112Sbostic varflag = 0; 60847112Sbostic } 60947112Sbostic *arglist.lastp = NULL; 61047112Sbostic *varlist.lastp = NULL; 61147112Sbostic expredir(cmd->ncmd.redirect); 61247112Sbostic argc = 0; 61347112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) 61447112Sbostic argc++; 61547112Sbostic argv = stalloc(sizeof (char *) * (argc + 1)); 616*55245Smarc 61753298Smarc for (sp = arglist.list ; sp ; sp = sp->next) { 61853298Smarc TRACE(("evalcommand arg: %s\n", sp->text)); 61947112Sbostic *argv++ = sp->text; 62053298Smarc } 62147112Sbostic *argv = NULL; 62247112Sbostic lastarg = NULL; 62347112Sbostic if (iflag && funcnest == 0 && argc > 0) 62447112Sbostic lastarg = argv[-1]; 62547112Sbostic argv -= argc; 62647112Sbostic 62747112Sbostic /* Print the command if xflag is set. */ 62847112Sbostic if (xflag) { 62947112Sbostic outc('+', &errout); 63047112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) { 63147112Sbostic outc(' ', &errout); 63247112Sbostic out2str(sp->text); 63347112Sbostic } 63447112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 63547112Sbostic outc(' ', &errout); 63647112Sbostic out2str(sp->text); 63747112Sbostic } 63847112Sbostic outc('\n', &errout); 63947112Sbostic flushout(&errout); 64047112Sbostic } 64147112Sbostic 64247112Sbostic /* Now locate the command. */ 64347112Sbostic if (argc == 0) { 64447112Sbostic cmdentry.cmdtype = CMDBUILTIN; 64547112Sbostic cmdentry.u.index = BLTINCMD; 64647112Sbostic } else { 64747112Sbostic find_command(argv[0], &cmdentry, 1); 64847112Sbostic if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 64947112Sbostic exitstatus = 2; 65047112Sbostic flushout(&errout); 65147112Sbostic return; 65247112Sbostic } 65347112Sbostic /* implement the bltin builtin here */ 65447112Sbostic if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 65547112Sbostic for (;;) { 65647112Sbostic argv++; 65747112Sbostic if (--argc == 0) 65847112Sbostic break; 65947112Sbostic if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 66047112Sbostic outfmt(&errout, "%s: not found\n", *argv); 66147112Sbostic exitstatus = 2; 66247112Sbostic flushout(&errout); 66347112Sbostic return; 66447112Sbostic } 66547112Sbostic if (cmdentry.u.index != BLTINCMD) 66647112Sbostic break; 66747112Sbostic } 66847112Sbostic } 66947112Sbostic } 67047112Sbostic 67147112Sbostic /* Fork off a child process if necessary. */ 67247112Sbostic if (cmd->ncmd.backgnd 67347112Sbostic || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0 67447112Sbostic || (flags & EV_BACKCMD) != 0 67547112Sbostic && (cmdentry.cmdtype != CMDBUILTIN 67647112Sbostic || cmdentry.u.index == DOTCMD 67747112Sbostic || cmdentry.u.index == EVALCMD)) { 67847112Sbostic jp = makejob(cmd, 1); 67947112Sbostic mode = cmd->ncmd.backgnd; 68047112Sbostic if (flags & EV_BACKCMD) { 68147112Sbostic mode = FORK_NOJOB; 68247112Sbostic if (pipe(pip) < 0) 68347112Sbostic error("Pipe call failed"); 68447112Sbostic } 68547112Sbostic if (forkshell(jp, cmd, mode) != 0) 68647112Sbostic goto parent; /* at end of routine */ 68747112Sbostic if (flags & EV_BACKCMD) { 68847112Sbostic FORCEINTON; 68947112Sbostic close(pip[0]); 69047112Sbostic if (pip[1] != 1) { 69147112Sbostic close(1); 69247112Sbostic copyfd(pip[1], 1); 69347112Sbostic close(pip[1]); 69447112Sbostic } 69547112Sbostic } 69647112Sbostic flags |= EV_EXIT; 69747112Sbostic } 69847112Sbostic 69947112Sbostic /* This is the child process if a fork occurred. */ 70047112Sbostic /* Execute the command. */ 70147112Sbostic if (cmdentry.cmdtype == CMDFUNCTION) { 70247112Sbostic trputs("Shell function: "); trargs(argv); 70347112Sbostic redirect(cmd->ncmd.redirect, REDIR_PUSH); 70447112Sbostic saveparam = shellparam; 70547112Sbostic shellparam.malloc = 0; 70647112Sbostic shellparam.nparam = argc - 1; 70747112Sbostic shellparam.p = argv + 1; 70847112Sbostic shellparam.optnext = NULL; 70947112Sbostic INTOFF; 71047112Sbostic savelocalvars = localvars; 71147112Sbostic localvars = NULL; 71247112Sbostic INTON; 71347112Sbostic if (setjmp(jmploc.loc)) { 71447112Sbostic if (exception == EXSHELLPROC) 71547112Sbostic freeparam((struct shparam *)&saveparam); 71647112Sbostic else { 71747112Sbostic freeparam(&shellparam); 71847112Sbostic shellparam = saveparam; 71947112Sbostic } 72047112Sbostic poplocalvars(); 72147112Sbostic localvars = savelocalvars; 72247112Sbostic handler = savehandler; 72347112Sbostic longjmp(handler->loc, 1); 72447112Sbostic } 72547112Sbostic savehandler = handler; 72647112Sbostic handler = &jmploc; 72747112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 72847112Sbostic mklocal(sp->text); 72947112Sbostic funcnest++; 73047112Sbostic evaltree(cmdentry.u.func, 0); 73147112Sbostic funcnest--; 73247112Sbostic INTOFF; 73347112Sbostic poplocalvars(); 73447112Sbostic localvars = savelocalvars; 73547112Sbostic freeparam(&shellparam); 73647112Sbostic shellparam = saveparam; 73747112Sbostic handler = savehandler; 73847112Sbostic popredir(); 73947112Sbostic INTON; 74047112Sbostic if (evalskip == SKIPFUNC) { 74147112Sbostic evalskip = 0; 74247112Sbostic skipcount = 0; 74347112Sbostic } 74447112Sbostic if (flags & EV_EXIT) 74547112Sbostic exitshell(exitstatus); 74647112Sbostic } else if (cmdentry.cmdtype == CMDBUILTIN) { 74747112Sbostic trputs("builtin command: "); trargs(argv); 74847112Sbostic mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 74947112Sbostic if (flags == EV_BACKCMD) { 75047112Sbostic memout.nleft = 0; 75147112Sbostic memout.nextc = memout.buf; 75247112Sbostic memout.bufsize = 64; 75347112Sbostic mode |= REDIR_BACKQ; 75447112Sbostic } 75547112Sbostic redirect(cmd->ncmd.redirect, mode); 75647112Sbostic savecmdname = commandname; 75747112Sbostic cmdenviron = varlist.list; 75847112Sbostic e = -1; 75947112Sbostic if (setjmp(jmploc.loc)) { 76047112Sbostic e = exception; 76147112Sbostic exitstatus = (e == EXINT)? SIGINT+128 : 2; 76247112Sbostic goto cmddone; 76347112Sbostic } 76447112Sbostic savehandler = handler; 76547112Sbostic handler = &jmploc; 76647112Sbostic commandname = argv[0]; 76747112Sbostic argptr = argv + 1; 76847112Sbostic optptr = NULL; /* initialize nextopt */ 76947112Sbostic exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 77047112Sbostic flushall(); 77147112Sbostic cmddone: 77247112Sbostic out1 = &output; 77347112Sbostic out2 = &errout; 77447112Sbostic freestdout(); 77547112Sbostic if (e != EXSHELLPROC) { 77647112Sbostic commandname = savecmdname; 77747112Sbostic if (flags & EV_EXIT) { 77847112Sbostic exitshell(exitstatus); 77947112Sbostic } 78047112Sbostic } 78147112Sbostic handler = savehandler; 78247112Sbostic if (e != -1) { 78347112Sbostic if (e != EXERROR || cmdentry.u.index == BLTINCMD 78447112Sbostic || cmdentry.u.index == DOTCMD 78547112Sbostic || cmdentry.u.index == EVALCMD 786*55245Smarc || cmdentry.u.index == HISTCMD 78747112Sbostic || cmdentry.u.index == EXECCMD) 78847112Sbostic exraise(e); 78947112Sbostic FORCEINTON; 79047112Sbostic } 79147112Sbostic if (cmdentry.u.index != EXECCMD) 79247112Sbostic popredir(); 79347112Sbostic if (flags == EV_BACKCMD) { 79447112Sbostic backcmd->buf = memout.buf; 79547112Sbostic backcmd->nleft = memout.nextc - memout.buf; 79647112Sbostic memout.buf = NULL; 79747112Sbostic } 79847112Sbostic } else { 79947112Sbostic trputs("normal command: "); trargs(argv); 80047112Sbostic clearredir(); 80147112Sbostic redirect(cmd->ncmd.redirect, 0); 80247112Sbostic if (varlist.list) { 80347112Sbostic p = stalloc(strlen(pathval()) + 1); 80447112Sbostic scopy(pathval(), p); 80547112Sbostic } else { 80647112Sbostic p = pathval(); 80747112Sbostic } 80847112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 80947112Sbostic setvareq(sp->text, VEXPORT|VSTACK); 81047112Sbostic envp = environment(); 81147112Sbostic shellexec(argv, envp, p, cmdentry.u.index); 81247112Sbostic /*NOTREACHED*/ 81347112Sbostic } 81447112Sbostic goto out; 81547112Sbostic 81647112Sbostic parent: /* parent process gets here (if we forked) */ 81747112Sbostic if (mode == 0) { /* argument to fork */ 81847112Sbostic INTOFF; 81947112Sbostic exitstatus = waitforjob(jp); 82047112Sbostic INTON; 82147112Sbostic } else if (mode == 2) { 82247112Sbostic backcmd->fd = pip[0]; 82347112Sbostic close(pip[1]); 82447112Sbostic backcmd->jp = jp; 82547112Sbostic } 82647112Sbostic 82747112Sbostic out: 82847112Sbostic if (lastarg) 82947112Sbostic setvar("_", lastarg, 0); 83047112Sbostic popstackmark(&smark); 83147112Sbostic } 83247112Sbostic 83347112Sbostic 83447112Sbostic 83547112Sbostic /* 83647112Sbostic * Search for a command. This is called before we fork so that the 83747112Sbostic * location of the command will be available in the parent as well as 83847112Sbostic * the child. The check for "goodname" is an overly conservative 83947112Sbostic * check that the name will not be subject to expansion. 84047112Sbostic */ 84147112Sbostic 84247112Sbostic STATIC void 84347112Sbostic prehash(n) 84447112Sbostic union node *n; 84547112Sbostic { 84647112Sbostic struct cmdentry entry; 84747112Sbostic 84847112Sbostic if (n->type == NCMD && goodname(n->ncmd.args->narg.text)) 84947112Sbostic find_command(n->ncmd.args->narg.text, &entry, 0); 85047112Sbostic } 85147112Sbostic 85247112Sbostic 85347112Sbostic 85447112Sbostic /* 85547112Sbostic * Builtin commands. Builtin commands whose functions are closely 85647112Sbostic * tied to evaluation are implemented here. 85747112Sbostic */ 85847112Sbostic 85947112Sbostic /* 86047112Sbostic * No command given, or a bltin command with no arguments. Set the 86147112Sbostic * specified variables. 86247112Sbostic */ 86347112Sbostic 86447112Sbostic bltincmd(argc, argv) char **argv; { 86547112Sbostic listsetvar(cmdenviron); 86647112Sbostic return exitstatus; 86747112Sbostic } 86847112Sbostic 86947112Sbostic 87047112Sbostic /* 87147112Sbostic * Handle break and continue commands. Break, continue, and return are 87247112Sbostic * all handled by setting the evalskip flag. The evaluation routines 87347112Sbostic * above all check this flag, and if it is set they start skipping 87447112Sbostic * commands rather than executing them. The variable skipcount is 87547112Sbostic * the number of loops to break/continue, or the number of function 87647112Sbostic * levels to return. (The latter is always 1.) It should probably 87747112Sbostic * be an error to break out of more loops than exist, but it isn't 87847112Sbostic * in the standard shell so we don't make it one here. 87947112Sbostic */ 88047112Sbostic 88147112Sbostic breakcmd(argc, argv) char **argv; { 88247112Sbostic int n; 88347112Sbostic 88447112Sbostic n = 1; 88547112Sbostic if (argc > 1) 88647112Sbostic n = number(argv[1]); 88747112Sbostic if (n > loopnest) 88847112Sbostic n = loopnest; 88947112Sbostic if (n > 0) { 89047112Sbostic evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 89147112Sbostic skipcount = n; 89247112Sbostic } 89347112Sbostic return 0; 89447112Sbostic } 89547112Sbostic 89647112Sbostic 89747112Sbostic /* 89847112Sbostic * The return command. 89947112Sbostic */ 90047112Sbostic 90147112Sbostic returncmd(argc, argv) char **argv; { 90247112Sbostic int ret; 90347112Sbostic 90447112Sbostic ret = exitstatus; 90547112Sbostic if (argc > 1) 90647112Sbostic ret = number(argv[1]); 90747112Sbostic if (funcnest) { 90847112Sbostic evalskip = SKIPFUNC; 90947112Sbostic skipcount = 1; 91047112Sbostic } 91147112Sbostic return ret; 91247112Sbostic } 91347112Sbostic 91447112Sbostic 91547112Sbostic truecmd(argc, argv) char **argv; { 91647112Sbostic return 0; 91747112Sbostic } 91847112Sbostic 91947112Sbostic 92047112Sbostic execcmd(argc, argv) char **argv; { 92147112Sbostic if (argc > 1) { 92247112Sbostic iflag = 0; /* exit on error */ 923*55245Smarc mflag = 0; 924*55245Smarc optschanged(); 92547112Sbostic shellexec(argv + 1, environment(), pathval(), 0); 92647112Sbostic 92747112Sbostic } 92847112Sbostic return 0; 92947112Sbostic } 930