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" 6355245Smarc #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")); 19755245Smarc exitstatus = 0; 19855245Smarc goto out; 19947112Sbostic } 20055245Smarc 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; 531*55798Smarc exitstatus = 0; 532*55798Smarc if (n == NULL) 533*55798Smarc goto out; 53447112Sbostic if (n->type == NCMD) { 53547112Sbostic evalcommand(n, EV_BACKCMD, result); 53647112Sbostic } else { 53747112Sbostic if (pipe(pip) < 0) 53847112Sbostic error("Pipe call failed"); 53947112Sbostic jp = makejob(n, 1); 54047112Sbostic if (forkshell(jp, n, FORK_NOJOB) == 0) { 54147112Sbostic FORCEINTON; 54247112Sbostic close(pip[0]); 54347112Sbostic if (pip[1] != 1) { 54447112Sbostic close(1); 54547112Sbostic copyfd(pip[1], 1); 54647112Sbostic close(pip[1]); 54747112Sbostic } 54847112Sbostic evaltree(n, EV_EXIT); 54947112Sbostic } 55047112Sbostic close(pip[1]); 55147112Sbostic result->fd = pip[0]; 55247112Sbostic result->jp = jp; 55347112Sbostic } 554*55798Smarc out: 55547112Sbostic popstackmark(&smark); 55647112Sbostic TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 55747112Sbostic result->fd, result->buf, result->nleft, result->jp)); 55847112Sbostic } 55947112Sbostic 56047112Sbostic 56147112Sbostic 56247112Sbostic /* 56347112Sbostic * Execute a simple command. 56447112Sbostic */ 56547112Sbostic 56647112Sbostic STATIC void 56747112Sbostic evalcommand(cmd, flags, backcmd) 56847112Sbostic union node *cmd; 56947112Sbostic struct backcmd *backcmd; 57047112Sbostic { 57147112Sbostic struct stackmark smark; 57247112Sbostic union node *argp; 57347112Sbostic struct arglist arglist; 57447112Sbostic struct arglist varlist; 57547112Sbostic char **argv; 57647112Sbostic int argc; 57747112Sbostic char **envp; 57847112Sbostic int varflag; 57947112Sbostic struct strlist *sp; 58047112Sbostic register char *p; 58147112Sbostic int mode; 58247112Sbostic int pip[2]; 58347112Sbostic struct cmdentry cmdentry; 58447112Sbostic struct job *jp; 58547112Sbostic struct jmploc jmploc; 58647112Sbostic struct jmploc *volatile savehandler; 58747112Sbostic char *volatile savecmdname; 58847112Sbostic volatile struct shparam saveparam; 58947112Sbostic struct localvar *volatile savelocalvars; 59047112Sbostic volatile int e; 59147112Sbostic char *lastarg; 59247112Sbostic 59347112Sbostic /* First expand the arguments. */ 59447112Sbostic TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags)); 59547112Sbostic setstackmark(&smark); 59647112Sbostic arglist.lastp = &arglist.list; 59747112Sbostic varlist.lastp = &varlist.list; 59847112Sbostic varflag = 1; 59947112Sbostic for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 60047112Sbostic p = argp->narg.text; 60147112Sbostic if (varflag && is_name(*p)) { 60247112Sbostic do { 60347112Sbostic p++; 60447112Sbostic } while (is_in_name(*p)); 60547112Sbostic if (*p == '=') { 60653298Smarc expandarg(argp, &varlist, EXP_VARTILDE); 60747112Sbostic continue; 60847112Sbostic } 60947112Sbostic } 61053298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 61147112Sbostic varflag = 0; 61247112Sbostic } 61347112Sbostic *arglist.lastp = NULL; 61447112Sbostic *varlist.lastp = NULL; 61547112Sbostic expredir(cmd->ncmd.redirect); 61647112Sbostic argc = 0; 61747112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) 61847112Sbostic argc++; 61947112Sbostic argv = stalloc(sizeof (char *) * (argc + 1)); 62055245Smarc 62153298Smarc for (sp = arglist.list ; sp ; sp = sp->next) { 62253298Smarc TRACE(("evalcommand arg: %s\n", sp->text)); 62347112Sbostic *argv++ = sp->text; 62453298Smarc } 62547112Sbostic *argv = NULL; 62647112Sbostic lastarg = NULL; 62747112Sbostic if (iflag && funcnest == 0 && argc > 0) 62847112Sbostic lastarg = argv[-1]; 62947112Sbostic argv -= argc; 63047112Sbostic 63147112Sbostic /* Print the command if xflag is set. */ 63247112Sbostic if (xflag) { 63347112Sbostic outc('+', &errout); 63447112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) { 63547112Sbostic outc(' ', &errout); 63647112Sbostic out2str(sp->text); 63747112Sbostic } 63847112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 63947112Sbostic outc(' ', &errout); 64047112Sbostic out2str(sp->text); 64147112Sbostic } 64247112Sbostic outc('\n', &errout); 64347112Sbostic flushout(&errout); 64447112Sbostic } 64547112Sbostic 64647112Sbostic /* Now locate the command. */ 64747112Sbostic if (argc == 0) { 64847112Sbostic cmdentry.cmdtype = CMDBUILTIN; 64947112Sbostic cmdentry.u.index = BLTINCMD; 65047112Sbostic } else { 65147112Sbostic find_command(argv[0], &cmdentry, 1); 65247112Sbostic if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 65347112Sbostic exitstatus = 2; 65447112Sbostic flushout(&errout); 65547112Sbostic return; 65647112Sbostic } 65747112Sbostic /* implement the bltin builtin here */ 65847112Sbostic if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 65947112Sbostic for (;;) { 66047112Sbostic argv++; 66147112Sbostic if (--argc == 0) 66247112Sbostic break; 66347112Sbostic if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 66447112Sbostic outfmt(&errout, "%s: not found\n", *argv); 66547112Sbostic exitstatus = 2; 66647112Sbostic flushout(&errout); 66747112Sbostic return; 66847112Sbostic } 66947112Sbostic if (cmdentry.u.index != BLTINCMD) 67047112Sbostic break; 67147112Sbostic } 67247112Sbostic } 67347112Sbostic } 67447112Sbostic 67547112Sbostic /* Fork off a child process if necessary. */ 67647112Sbostic if (cmd->ncmd.backgnd 67747112Sbostic || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0 67847112Sbostic || (flags & EV_BACKCMD) != 0 67947112Sbostic && (cmdentry.cmdtype != CMDBUILTIN 68047112Sbostic || cmdentry.u.index == DOTCMD 68147112Sbostic || cmdentry.u.index == EVALCMD)) { 68247112Sbostic jp = makejob(cmd, 1); 68347112Sbostic mode = cmd->ncmd.backgnd; 68447112Sbostic if (flags & EV_BACKCMD) { 68547112Sbostic mode = FORK_NOJOB; 68647112Sbostic if (pipe(pip) < 0) 68747112Sbostic error("Pipe call failed"); 68847112Sbostic } 68947112Sbostic if (forkshell(jp, cmd, mode) != 0) 69047112Sbostic goto parent; /* at end of routine */ 69147112Sbostic if (flags & EV_BACKCMD) { 69247112Sbostic FORCEINTON; 69347112Sbostic close(pip[0]); 69447112Sbostic if (pip[1] != 1) { 69547112Sbostic close(1); 69647112Sbostic copyfd(pip[1], 1); 69747112Sbostic close(pip[1]); 69847112Sbostic } 69947112Sbostic } 70047112Sbostic flags |= EV_EXIT; 70147112Sbostic } 70247112Sbostic 70347112Sbostic /* This is the child process if a fork occurred. */ 70447112Sbostic /* Execute the command. */ 70547112Sbostic if (cmdentry.cmdtype == CMDFUNCTION) { 70647112Sbostic trputs("Shell function: "); trargs(argv); 70747112Sbostic redirect(cmd->ncmd.redirect, REDIR_PUSH); 70847112Sbostic saveparam = shellparam; 70947112Sbostic shellparam.malloc = 0; 71047112Sbostic shellparam.nparam = argc - 1; 71147112Sbostic shellparam.p = argv + 1; 71247112Sbostic shellparam.optnext = NULL; 71347112Sbostic INTOFF; 71447112Sbostic savelocalvars = localvars; 71547112Sbostic localvars = NULL; 71647112Sbostic INTON; 71747112Sbostic if (setjmp(jmploc.loc)) { 71847112Sbostic if (exception == EXSHELLPROC) 71947112Sbostic freeparam((struct shparam *)&saveparam); 72047112Sbostic else { 72147112Sbostic freeparam(&shellparam); 72247112Sbostic shellparam = saveparam; 72347112Sbostic } 72447112Sbostic poplocalvars(); 72547112Sbostic localvars = savelocalvars; 72647112Sbostic handler = savehandler; 72747112Sbostic longjmp(handler->loc, 1); 72847112Sbostic } 72947112Sbostic savehandler = handler; 73047112Sbostic handler = &jmploc; 73147112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 73247112Sbostic mklocal(sp->text); 73347112Sbostic funcnest++; 73447112Sbostic evaltree(cmdentry.u.func, 0); 73547112Sbostic funcnest--; 73647112Sbostic INTOFF; 73747112Sbostic poplocalvars(); 73847112Sbostic localvars = savelocalvars; 73947112Sbostic freeparam(&shellparam); 74047112Sbostic shellparam = saveparam; 74147112Sbostic handler = savehandler; 74247112Sbostic popredir(); 74347112Sbostic INTON; 74447112Sbostic if (evalskip == SKIPFUNC) { 74547112Sbostic evalskip = 0; 74647112Sbostic skipcount = 0; 74747112Sbostic } 74847112Sbostic if (flags & EV_EXIT) 74947112Sbostic exitshell(exitstatus); 75047112Sbostic } else if (cmdentry.cmdtype == CMDBUILTIN) { 75147112Sbostic trputs("builtin command: "); trargs(argv); 75247112Sbostic mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 75347112Sbostic if (flags == EV_BACKCMD) { 75447112Sbostic memout.nleft = 0; 75547112Sbostic memout.nextc = memout.buf; 75647112Sbostic memout.bufsize = 64; 75747112Sbostic mode |= REDIR_BACKQ; 75847112Sbostic } 75947112Sbostic redirect(cmd->ncmd.redirect, mode); 76047112Sbostic savecmdname = commandname; 76147112Sbostic cmdenviron = varlist.list; 76247112Sbostic e = -1; 76347112Sbostic if (setjmp(jmploc.loc)) { 76447112Sbostic e = exception; 76547112Sbostic exitstatus = (e == EXINT)? SIGINT+128 : 2; 76647112Sbostic goto cmddone; 76747112Sbostic } 76847112Sbostic savehandler = handler; 76947112Sbostic handler = &jmploc; 77047112Sbostic commandname = argv[0]; 77147112Sbostic argptr = argv + 1; 77247112Sbostic optptr = NULL; /* initialize nextopt */ 77347112Sbostic exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 77447112Sbostic flushall(); 77547112Sbostic cmddone: 77647112Sbostic out1 = &output; 77747112Sbostic out2 = &errout; 77847112Sbostic freestdout(); 77947112Sbostic if (e != EXSHELLPROC) { 78047112Sbostic commandname = savecmdname; 78147112Sbostic if (flags & EV_EXIT) { 78247112Sbostic exitshell(exitstatus); 78347112Sbostic } 78447112Sbostic } 78547112Sbostic handler = savehandler; 78647112Sbostic if (e != -1) { 78747112Sbostic if (e != EXERROR || cmdentry.u.index == BLTINCMD 78847112Sbostic || cmdentry.u.index == DOTCMD 78947112Sbostic || cmdentry.u.index == EVALCMD 79055245Smarc || cmdentry.u.index == HISTCMD 79147112Sbostic || cmdentry.u.index == EXECCMD) 79247112Sbostic exraise(e); 79347112Sbostic FORCEINTON; 79447112Sbostic } 79547112Sbostic if (cmdentry.u.index != EXECCMD) 79647112Sbostic popredir(); 79747112Sbostic if (flags == EV_BACKCMD) { 79847112Sbostic backcmd->buf = memout.buf; 79947112Sbostic backcmd->nleft = memout.nextc - memout.buf; 80047112Sbostic memout.buf = NULL; 80147112Sbostic } 80247112Sbostic } else { 80347112Sbostic trputs("normal command: "); trargs(argv); 80447112Sbostic clearredir(); 80547112Sbostic redirect(cmd->ncmd.redirect, 0); 80647112Sbostic if (varlist.list) { 80747112Sbostic p = stalloc(strlen(pathval()) + 1); 80847112Sbostic scopy(pathval(), p); 80947112Sbostic } else { 81047112Sbostic p = pathval(); 81147112Sbostic } 81247112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 81347112Sbostic setvareq(sp->text, VEXPORT|VSTACK); 81447112Sbostic envp = environment(); 81547112Sbostic shellexec(argv, envp, p, cmdentry.u.index); 81647112Sbostic /*NOTREACHED*/ 81747112Sbostic } 81847112Sbostic goto out; 81947112Sbostic 82047112Sbostic parent: /* parent process gets here (if we forked) */ 82147112Sbostic if (mode == 0) { /* argument to fork */ 82247112Sbostic INTOFF; 82347112Sbostic exitstatus = waitforjob(jp); 82447112Sbostic INTON; 82547112Sbostic } else if (mode == 2) { 82647112Sbostic backcmd->fd = pip[0]; 82747112Sbostic close(pip[1]); 82847112Sbostic backcmd->jp = jp; 82947112Sbostic } 83047112Sbostic 83147112Sbostic out: 83247112Sbostic if (lastarg) 83347112Sbostic setvar("_", lastarg, 0); 83447112Sbostic popstackmark(&smark); 83547112Sbostic } 83647112Sbostic 83747112Sbostic 83847112Sbostic 83947112Sbostic /* 84047112Sbostic * Search for a command. This is called before we fork so that the 84147112Sbostic * location of the command will be available in the parent as well as 84247112Sbostic * the child. The check for "goodname" is an overly conservative 84347112Sbostic * check that the name will not be subject to expansion. 84447112Sbostic */ 84547112Sbostic 84647112Sbostic STATIC void 84747112Sbostic prehash(n) 84847112Sbostic union node *n; 84947112Sbostic { 85047112Sbostic struct cmdentry entry; 85147112Sbostic 85247112Sbostic if (n->type == NCMD && goodname(n->ncmd.args->narg.text)) 85347112Sbostic find_command(n->ncmd.args->narg.text, &entry, 0); 85447112Sbostic } 85547112Sbostic 85647112Sbostic 85747112Sbostic 85847112Sbostic /* 85947112Sbostic * Builtin commands. Builtin commands whose functions are closely 86047112Sbostic * tied to evaluation are implemented here. 86147112Sbostic */ 86247112Sbostic 86347112Sbostic /* 86447112Sbostic * No command given, or a bltin command with no arguments. Set the 86547112Sbostic * specified variables. 86647112Sbostic */ 86747112Sbostic 86847112Sbostic bltincmd(argc, argv) char **argv; { 86947112Sbostic listsetvar(cmdenviron); 87047112Sbostic return exitstatus; 87147112Sbostic } 87247112Sbostic 87347112Sbostic 87447112Sbostic /* 87547112Sbostic * Handle break and continue commands. Break, continue, and return are 87647112Sbostic * all handled by setting the evalskip flag. The evaluation routines 87747112Sbostic * above all check this flag, and if it is set they start skipping 87847112Sbostic * commands rather than executing them. The variable skipcount is 87947112Sbostic * the number of loops to break/continue, or the number of function 88047112Sbostic * levels to return. (The latter is always 1.) It should probably 88147112Sbostic * be an error to break out of more loops than exist, but it isn't 88247112Sbostic * in the standard shell so we don't make it one here. 88347112Sbostic */ 88447112Sbostic 88547112Sbostic breakcmd(argc, argv) char **argv; { 88647112Sbostic int n; 88747112Sbostic 88847112Sbostic n = 1; 88947112Sbostic if (argc > 1) 89047112Sbostic n = number(argv[1]); 89147112Sbostic if (n > loopnest) 89247112Sbostic n = loopnest; 89347112Sbostic if (n > 0) { 89447112Sbostic evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 89547112Sbostic skipcount = n; 89647112Sbostic } 89747112Sbostic return 0; 89847112Sbostic } 89947112Sbostic 90047112Sbostic 90147112Sbostic /* 90247112Sbostic * The return command. 90347112Sbostic */ 90447112Sbostic 90547112Sbostic returncmd(argc, argv) char **argv; { 90647112Sbostic int ret; 90747112Sbostic 90847112Sbostic ret = exitstatus; 90947112Sbostic if (argc > 1) 91047112Sbostic ret = number(argv[1]); 91147112Sbostic if (funcnest) { 91247112Sbostic evalskip = SKIPFUNC; 91347112Sbostic skipcount = 1; 91447112Sbostic } 91547112Sbostic return ret; 91647112Sbostic } 91747112Sbostic 91847112Sbostic 91947112Sbostic truecmd(argc, argv) char **argv; { 92047112Sbostic return 0; 92147112Sbostic } 92247112Sbostic 92347112Sbostic 92447112Sbostic execcmd(argc, argv) char **argv; { 92547112Sbostic if (argc > 1) { 92647112Sbostic iflag = 0; /* exit on error */ 92755245Smarc mflag = 0; 92855245Smarc optschanged(); 92947112Sbostic shellexec(argv + 1, environment(), pathval(), 0); 93047112Sbostic 93147112Sbostic } 93247112Sbostic return 0; 93347112Sbostic } 934