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*69549Schristos static char sccsid[] = "@(#)eval.c 8.8 (Berkeley) 05/19/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 */ 6669469Schristos int oexitstatus; /* saved exit status */ 6747112Sbostic 6847112Sbostic 6969272Schristos STATIC void evalloop __P((union node *)); 7069272Schristos STATIC void evalfor __P((union node *)); 7169272Schristos STATIC void evalcase __P((union node *, int)); 7269272Schristos STATIC void evalsubshell __P((union node *, int)); 7369272Schristos STATIC void expredir __P((union node *)); 7469272Schristos STATIC void evalpipe __P((union node *)); 7569272Schristos STATIC void evalcommand __P((union node *, int, struct backcmd *)); 7669272Schristos STATIC void prehash __P((union node *)); 7747112Sbostic 7847112Sbostic 7947112Sbostic /* 8047112Sbostic * Called to reset things after an exception. 8147112Sbostic */ 8247112Sbostic 8347112Sbostic #ifdef mkinit 8447112Sbostic INCLUDE "eval.h" 8547112Sbostic 8647112Sbostic RESET { 8747112Sbostic evalskip = 0; 8847112Sbostic loopnest = 0; 8947112Sbostic funcnest = 0; 9047112Sbostic } 9147112Sbostic 9247112Sbostic SHELLPROC { 9347112Sbostic exitstatus = 0; 9447112Sbostic } 9547112Sbostic #endif 9647112Sbostic 9747112Sbostic 9847112Sbostic 9947112Sbostic /* 10047292Smarc * The eval commmand. 10147112Sbostic */ 10247112Sbostic 10369272Schristos int 10447292Smarc evalcmd(argc, argv) 10569272Schristos int argc; 10647292Smarc char **argv; 10747292Smarc { 10847292Smarc char *p; 10947292Smarc char *concat; 11047292Smarc char **ap; 11147112Sbostic 11247292Smarc if (argc > 1) { 11347292Smarc p = argv[1]; 11447292Smarc if (argc > 2) { 11547292Smarc STARTSTACKSTR(concat); 11647292Smarc ap = argv + 2; 11747292Smarc for (;;) { 11847292Smarc while (*p) 11947292Smarc STPUTC(*p++, concat); 12047292Smarc if ((p = *ap++) == NULL) 12147292Smarc break; 12247292Smarc STPUTC(' ', concat); 12347292Smarc } 12447292Smarc STPUTC('\0', concat); 12547292Smarc p = grabstackstr(concat); 12647292Smarc } 12747292Smarc evalstring(p); 12847292Smarc } 12947292Smarc return exitstatus; 13047112Sbostic } 13147112Sbostic 13247112Sbostic 13347112Sbostic /* 13447112Sbostic * Execute a command or commands contained in a string. 13547112Sbostic */ 13647112Sbostic 13747112Sbostic void 13847112Sbostic evalstring(s) 13947112Sbostic char *s; 14047112Sbostic { 14147112Sbostic union node *n; 14247112Sbostic struct stackmark smark; 14347112Sbostic 14447112Sbostic setstackmark(&smark); 14547112Sbostic setinputstring(s, 1); 14647112Sbostic while ((n = parsecmd(0)) != NEOF) { 14747112Sbostic evaltree(n, 0); 14847112Sbostic popstackmark(&smark); 14947112Sbostic } 15047112Sbostic popfile(); 15147112Sbostic popstackmark(&smark); 15247112Sbostic } 15347112Sbostic 15447112Sbostic 15547112Sbostic 15647112Sbostic /* 15747112Sbostic * Evaluate a parse tree. The value is left in the global variable 15847112Sbostic * exitstatus. 15947112Sbostic */ 16047112Sbostic 16147112Sbostic void 16247112Sbostic evaltree(n, flags) 16347112Sbostic union node *n; 16469272Schristos int flags; 16569272Schristos { 16647112Sbostic if (n == NULL) { 16747112Sbostic TRACE(("evaltree(NULL) called\n")); 16855245Smarc exitstatus = 0; 16955245Smarc goto out; 17047112Sbostic } 17169272Schristos #ifndef NO_HISTORY 17255245Smarc displayhist = 1; /* show history substitutions done with fc */ 17369272Schristos #endif 17469272Schristos TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); 17547112Sbostic switch (n->type) { 17647112Sbostic case NSEMI: 17747112Sbostic evaltree(n->nbinary.ch1, 0); 17847112Sbostic if (evalskip) 17947112Sbostic goto out; 18047112Sbostic evaltree(n->nbinary.ch2, flags); 18147112Sbostic break; 18247112Sbostic case NAND: 18347112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 18447112Sbostic if (evalskip || exitstatus != 0) 18547112Sbostic goto out; 18647112Sbostic evaltree(n->nbinary.ch2, flags); 18747112Sbostic break; 18847112Sbostic case NOR: 18947112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 19047112Sbostic if (evalskip || exitstatus == 0) 19147112Sbostic goto out; 19247112Sbostic evaltree(n->nbinary.ch2, flags); 19347112Sbostic break; 19447112Sbostic case NREDIR: 19547112Sbostic expredir(n->nredir.redirect); 19647112Sbostic redirect(n->nredir.redirect, REDIR_PUSH); 19747112Sbostic evaltree(n->nredir.n, flags); 19847112Sbostic popredir(); 19947112Sbostic break; 20047112Sbostic case NSUBSHELL: 20147112Sbostic evalsubshell(n, flags); 20247112Sbostic break; 20347112Sbostic case NBACKGND: 20447112Sbostic evalsubshell(n, flags); 20547112Sbostic break; 20647982Smarc case NIF: { 20769402Schristos int status; 20847982Smarc 20947112Sbostic evaltree(n->nif.test, EV_TESTED); 21069402Schristos status = exitstatus; 21169402Schristos exitstatus = 0; 21247112Sbostic if (evalskip) 21347112Sbostic goto out; 21469402Schristos if (status == 0) 21547112Sbostic evaltree(n->nif.ifpart, flags); 21669402Schristos else if (n->nif.elsepart) 21747112Sbostic evaltree(n->nif.elsepart, flags); 21847112Sbostic break; 21947982Smarc } 22047112Sbostic case NWHILE: 22147112Sbostic case NUNTIL: 22247112Sbostic evalloop(n); 22347112Sbostic break; 22447112Sbostic case NFOR: 22547112Sbostic evalfor(n); 22647112Sbostic break; 22747112Sbostic case NCASE: 22847112Sbostic evalcase(n, flags); 22947112Sbostic break; 23047112Sbostic case NDEFUN: 23147112Sbostic defun(n->narg.text, n->narg.next); 23247112Sbostic exitstatus = 0; 23347112Sbostic break; 23453175Smarc case NNOT: 23553175Smarc evaltree(n->nnot.com, EV_TESTED); 23653175Smarc exitstatus = !exitstatus; 23753175Smarc break; 23853175Smarc 23947112Sbostic case NPIPE: 24047112Sbostic evalpipe(n); 24147112Sbostic break; 24247112Sbostic case NCMD: 24347112Sbostic evalcommand(n, flags, (struct backcmd *)NULL); 24447112Sbostic break; 24547112Sbostic default: 24647112Sbostic out1fmt("Node type = %d\n", n->type); 24747112Sbostic flushout(&output); 24847112Sbostic break; 24947112Sbostic } 25047112Sbostic out: 25147112Sbostic if (pendingsigs) 25247112Sbostic dotrap(); 25347112Sbostic if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 25447112Sbostic exitshell(exitstatus); 25547112Sbostic } 25647112Sbostic 25747112Sbostic 25847112Sbostic STATIC void 25947112Sbostic evalloop(n) 26047112Sbostic union node *n; 26169391Schristos { 26247112Sbostic int status; 26347112Sbostic 26447112Sbostic loopnest++; 26547112Sbostic status = 0; 26647112Sbostic for (;;) { 26747112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 26847112Sbostic if (evalskip) { 26947112Sbostic skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 27047112Sbostic evalskip = 0; 27147112Sbostic continue; 27247112Sbostic } 27347112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 27447112Sbostic evalskip = 0; 27547112Sbostic break; 27647112Sbostic } 27747112Sbostic if (n->type == NWHILE) { 27847112Sbostic if (exitstatus != 0) 27947112Sbostic break; 28047112Sbostic } else { 28147112Sbostic if (exitstatus == 0) 28247112Sbostic break; 28347112Sbostic } 28447112Sbostic evaltree(n->nbinary.ch2, 0); 28547112Sbostic status = exitstatus; 28647112Sbostic if (evalskip) 28747112Sbostic goto skipping; 28847112Sbostic } 28947112Sbostic loopnest--; 29047112Sbostic exitstatus = status; 29147112Sbostic } 29247112Sbostic 29347112Sbostic 29447112Sbostic 29547112Sbostic STATIC void 29647112Sbostic evalfor(n) 29769391Schristos union node *n; 29869391Schristos { 29947112Sbostic struct arglist arglist; 30047112Sbostic union node *argp; 30147112Sbostic struct strlist *sp; 30247112Sbostic struct stackmark smark; 30347112Sbostic 30447112Sbostic setstackmark(&smark); 30547112Sbostic arglist.lastp = &arglist.list; 30647112Sbostic for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 30769469Schristos oexitstatus = exitstatus; 30853298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 30947112Sbostic if (evalskip) 31047112Sbostic goto out; 31147112Sbostic } 31247112Sbostic *arglist.lastp = NULL; 31347112Sbostic 31447112Sbostic exitstatus = 0; 31547112Sbostic loopnest++; 31647112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 31747112Sbostic setvar(n->nfor.var, sp->text, 0); 31847112Sbostic evaltree(n->nfor.body, 0); 31947112Sbostic if (evalskip) { 32047112Sbostic if (evalskip == SKIPCONT && --skipcount <= 0) { 32147112Sbostic evalskip = 0; 32247112Sbostic continue; 32347112Sbostic } 32447112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 32547112Sbostic evalskip = 0; 32647112Sbostic break; 32747112Sbostic } 32847112Sbostic } 32947112Sbostic loopnest--; 33047112Sbostic out: 33147112Sbostic popstackmark(&smark); 33247112Sbostic } 33347112Sbostic 33447112Sbostic 33547112Sbostic 33647112Sbostic STATIC void 33747112Sbostic evalcase(n, flags) 33847112Sbostic union node *n; 33969272Schristos int flags; 34069272Schristos { 34147112Sbostic union node *cp; 34247112Sbostic union node *patp; 34347112Sbostic struct arglist arglist; 34447112Sbostic struct stackmark smark; 34547112Sbostic 34647112Sbostic setstackmark(&smark); 34747112Sbostic arglist.lastp = &arglist.list; 34869469Schristos oexitstatus = exitstatus; 34953298Smarc expandarg(n->ncase.expr, &arglist, EXP_TILDE); 35047112Sbostic for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 35147112Sbostic for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 35247112Sbostic if (casematch(patp, arglist.list->text)) { 35347112Sbostic if (evalskip == 0) { 35447112Sbostic evaltree(cp->nclist.body, flags); 35547112Sbostic } 35647112Sbostic goto out; 35747112Sbostic } 35847112Sbostic } 35947112Sbostic } 36047112Sbostic out: 36147112Sbostic popstackmark(&smark); 36247112Sbostic } 36347112Sbostic 36447112Sbostic 36547112Sbostic 36647112Sbostic /* 36747112Sbostic * Kick off a subshell to evaluate a tree. 36847112Sbostic */ 36947112Sbostic 37047112Sbostic STATIC void 37147112Sbostic evalsubshell(n, flags) 37247112Sbostic union node *n; 37369272Schristos int flags; 37469272Schristos { 37547112Sbostic struct job *jp; 37647112Sbostic int backgnd = (n->type == NBACKGND); 37747112Sbostic 37847112Sbostic expredir(n->nredir.redirect); 37947112Sbostic jp = makejob(n, 1); 38047112Sbostic if (forkshell(jp, n, backgnd) == 0) { 38147112Sbostic if (backgnd) 38247112Sbostic flags &=~ EV_TESTED; 38347112Sbostic redirect(n->nredir.redirect, 0); 38447112Sbostic evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 38547112Sbostic } 38647112Sbostic if (! backgnd) { 38747112Sbostic INTOFF; 38847112Sbostic exitstatus = waitforjob(jp); 38947112Sbostic INTON; 39047112Sbostic } 39147112Sbostic } 39247112Sbostic 39347112Sbostic 39447112Sbostic 39547112Sbostic /* 39647112Sbostic * Compute the names of the files in a redirection list. 39747112Sbostic */ 39847112Sbostic 39947112Sbostic STATIC void 40047112Sbostic expredir(n) 40147112Sbostic union node *n; 40269391Schristos { 40347112Sbostic register union node *redir; 40447112Sbostic 40547112Sbostic for (redir = n ; redir ; redir = redir->nfile.next) { 40669272Schristos struct arglist fn; 40769272Schristos fn.lastp = &fn.list; 40869469Schristos oexitstatus = exitstatus; 40969272Schristos switch (redir->type) { 41069272Schristos case NFROM: 41169272Schristos case NTO: 41269272Schristos case NAPPEND: 41353298Smarc expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 41447112Sbostic redir->nfile.expfname = fn.list->text; 41569272Schristos break; 41669272Schristos case NFROMFD: 41769272Schristos case NTOFD: 41869272Schristos if (redir->ndup.vname) { 41969272Schristos expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 42069272Schristos fixredir(redir, fn.list->text, 1); 42169272Schristos } 42269272Schristos break; 42347112Sbostic } 42447112Sbostic } 42547112Sbostic } 42647112Sbostic 42747112Sbostic 42847112Sbostic 42947112Sbostic /* 43047112Sbostic * Evaluate a pipeline. All the processes in the pipeline are children 43147112Sbostic * of the process creating the pipeline. (This differs from some versions 43247112Sbostic * of the shell, which make the last process in a pipeline the parent 43347112Sbostic * of all the rest.) 43447112Sbostic */ 43547112Sbostic 43647112Sbostic STATIC void 43747112Sbostic evalpipe(n) 43847112Sbostic union node *n; 43969391Schristos { 44047112Sbostic struct job *jp; 44147112Sbostic struct nodelist *lp; 44247112Sbostic int pipelen; 44347112Sbostic int prevfd; 44447112Sbostic int pip[2]; 44547112Sbostic 44669272Schristos TRACE(("evalpipe(0x%lx) called\n", (long)n)); 44747112Sbostic pipelen = 0; 44847112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 44947112Sbostic pipelen++; 45047112Sbostic INTOFF; 45147112Sbostic jp = makejob(n, pipelen); 45247112Sbostic prevfd = -1; 45347112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 45447112Sbostic prehash(lp->n); 45547112Sbostic pip[1] = -1; 45647112Sbostic if (lp->next) { 45747112Sbostic if (pipe(pip) < 0) { 45847112Sbostic close(prevfd); 45947112Sbostic error("Pipe call failed"); 46047112Sbostic } 46147112Sbostic } 46247112Sbostic if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 46347112Sbostic INTON; 46447112Sbostic if (prevfd > 0) { 46547112Sbostic close(0); 46647112Sbostic copyfd(prevfd, 0); 46747112Sbostic close(prevfd); 46847112Sbostic } 46947112Sbostic if (pip[1] >= 0) { 47047112Sbostic close(pip[0]); 47147112Sbostic if (pip[1] != 1) { 47247112Sbostic close(1); 47347112Sbostic copyfd(pip[1], 1); 47447112Sbostic close(pip[1]); 47547112Sbostic } 47647112Sbostic } 47747112Sbostic evaltree(lp->n, EV_EXIT); 47847112Sbostic } 47947112Sbostic if (prevfd >= 0) 48047112Sbostic close(prevfd); 48147112Sbostic prevfd = pip[0]; 48247112Sbostic close(pip[1]); 48347112Sbostic } 48447112Sbostic INTON; 48547112Sbostic if (n->npipe.backgnd == 0) { 48647112Sbostic INTOFF; 48747112Sbostic exitstatus = waitforjob(jp); 48847112Sbostic TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 48947112Sbostic INTON; 49047112Sbostic } 49147112Sbostic } 49247112Sbostic 49347112Sbostic 49447112Sbostic 49547112Sbostic /* 49647112Sbostic * Execute a command inside back quotes. If it's a builtin command, we 49747112Sbostic * want to save its output in a block obtained from malloc. Otherwise 49847112Sbostic * we fork off a subprocess and get the output of the command via a pipe. 49947112Sbostic * Should be called with interrupts off. 50047112Sbostic */ 50147112Sbostic 50247112Sbostic void 50347112Sbostic evalbackcmd(n, result) 50447112Sbostic union node *n; 50547112Sbostic struct backcmd *result; 50669391Schristos { 50747112Sbostic int pip[2]; 50847112Sbostic struct job *jp; 50947112Sbostic struct stackmark smark; /* unnecessary */ 51047112Sbostic 51147112Sbostic setstackmark(&smark); 51247112Sbostic result->fd = -1; 51347112Sbostic result->buf = NULL; 51447112Sbostic result->nleft = 0; 51547112Sbostic result->jp = NULL; 51669469Schristos if (n == NULL) { 51769469Schristos exitstatus = 0; 51855798Smarc goto out; 51969469Schristos } 52047112Sbostic if (n->type == NCMD) { 52169469Schristos exitstatus = oexitstatus; 52247112Sbostic evalcommand(n, EV_BACKCMD, result); 52347112Sbostic } else { 52469469Schristos exitstatus = 0; 52547112Sbostic if (pipe(pip) < 0) 52647112Sbostic error("Pipe call failed"); 52747112Sbostic jp = makejob(n, 1); 52847112Sbostic if (forkshell(jp, n, FORK_NOJOB) == 0) { 52947112Sbostic FORCEINTON; 53047112Sbostic close(pip[0]); 53147112Sbostic if (pip[1] != 1) { 53247112Sbostic close(1); 53347112Sbostic copyfd(pip[1], 1); 53447112Sbostic close(pip[1]); 53547112Sbostic } 53647112Sbostic evaltree(n, EV_EXIT); 53747112Sbostic } 53847112Sbostic close(pip[1]); 53947112Sbostic result->fd = pip[0]; 54047112Sbostic result->jp = jp; 54147112Sbostic } 54255798Smarc out: 54347112Sbostic popstackmark(&smark); 54447112Sbostic TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 54547112Sbostic result->fd, result->buf, result->nleft, result->jp)); 54647112Sbostic } 54747112Sbostic 54847112Sbostic 54947112Sbostic 55047112Sbostic /* 55147112Sbostic * Execute a simple command. 55247112Sbostic */ 55347112Sbostic 55447112Sbostic STATIC void 55547112Sbostic evalcommand(cmd, flags, backcmd) 55647112Sbostic union node *cmd; 55769272Schristos int flags; 55847112Sbostic struct backcmd *backcmd; 55969272Schristos { 56047112Sbostic struct stackmark smark; 56147112Sbostic union node *argp; 56247112Sbostic struct arglist arglist; 56347112Sbostic struct arglist varlist; 56447112Sbostic char **argv; 56547112Sbostic int argc; 56647112Sbostic char **envp; 56747112Sbostic int varflag; 56847112Sbostic struct strlist *sp; 56947112Sbostic int mode; 57047112Sbostic int pip[2]; 57147112Sbostic struct cmdentry cmdentry; 57247112Sbostic struct job *jp; 57347112Sbostic struct jmploc jmploc; 57447112Sbostic struct jmploc *volatile savehandler; 57547112Sbostic char *volatile savecmdname; 57647112Sbostic volatile struct shparam saveparam; 57747112Sbostic struct localvar *volatile savelocalvars; 57847112Sbostic volatile int e; 57947112Sbostic char *lastarg; 58069272Schristos #if __GNUC__ 58169272Schristos /* Avoid longjmp clobbering */ 58269272Schristos (void) &argv; 58369272Schristos (void) &argc; 58469272Schristos (void) &lastarg; 58569272Schristos (void) &flags; 58669272Schristos #endif 58747112Sbostic 58847112Sbostic /* First expand the arguments. */ 58969272Schristos TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 59047112Sbostic setstackmark(&smark); 59147112Sbostic arglist.lastp = &arglist.list; 59247112Sbostic varlist.lastp = &varlist.list; 59347112Sbostic varflag = 1; 59469469Schristos oexitstatus = exitstatus; 59569469Schristos exitstatus = 0; 59647112Sbostic for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 59769272Schristos char *p = argp->narg.text; 59847112Sbostic if (varflag && is_name(*p)) { 59947112Sbostic do { 60047112Sbostic p++; 60147112Sbostic } while (is_in_name(*p)); 60247112Sbostic if (*p == '=') { 60353298Smarc expandarg(argp, &varlist, EXP_VARTILDE); 60447112Sbostic continue; 60547112Sbostic } 60647112Sbostic } 60753298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 60847112Sbostic varflag = 0; 60947112Sbostic } 61047112Sbostic *arglist.lastp = NULL; 61147112Sbostic *varlist.lastp = NULL; 61247112Sbostic expredir(cmd->ncmd.redirect); 61347112Sbostic argc = 0; 61447112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) 61547112Sbostic argc++; 61647112Sbostic argv = stalloc(sizeof (char *) * (argc + 1)); 61755245Smarc 61853298Smarc for (sp = arglist.list ; sp ; sp = sp->next) { 61953298Smarc TRACE(("evalcommand arg: %s\n", sp->text)); 62047112Sbostic *argv++ = sp->text; 62153298Smarc } 62247112Sbostic *argv = NULL; 62347112Sbostic lastarg = NULL; 62447112Sbostic if (iflag && funcnest == 0 && argc > 0) 62547112Sbostic lastarg = argv[-1]; 62647112Sbostic argv -= argc; 62747112Sbostic 62847112Sbostic /* Print the command if xflag is set. */ 62947112Sbostic if (xflag) { 63047112Sbostic outc('+', &errout); 63147112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) { 63247112Sbostic outc(' ', &errout); 63347112Sbostic out2str(sp->text); 63447112Sbostic } 63547112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 63647112Sbostic outc(' ', &errout); 63747112Sbostic out2str(sp->text); 63847112Sbostic } 63947112Sbostic outc('\n', &errout); 64047112Sbostic flushout(&errout); 64147112Sbostic } 64247112Sbostic 64347112Sbostic /* Now locate the command. */ 64447112Sbostic if (argc == 0) { 64547112Sbostic cmdentry.cmdtype = CMDBUILTIN; 64647112Sbostic cmdentry.u.index = BLTINCMD; 64747112Sbostic } else { 64847112Sbostic find_command(argv[0], &cmdentry, 1); 64947112Sbostic if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 650*69549Schristos exitstatus = 1; 65147112Sbostic flushout(&errout); 65247112Sbostic return; 65347112Sbostic } 65447112Sbostic /* implement the bltin builtin here */ 65547112Sbostic if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 65647112Sbostic for (;;) { 65747112Sbostic argv++; 65847112Sbostic if (--argc == 0) 65947112Sbostic break; 66047112Sbostic if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 66147112Sbostic outfmt(&errout, "%s: not found\n", *argv); 662*69549Schristos exitstatus = 1; 66347112Sbostic flushout(&errout); 66447112Sbostic return; 66547112Sbostic } 66647112Sbostic if (cmdentry.u.index != BLTINCMD) 66747112Sbostic break; 66847112Sbostic } 66947112Sbostic } 67047112Sbostic } 67147112Sbostic 67247112Sbostic /* Fork off a child process if necessary. */ 67347112Sbostic if (cmd->ncmd.backgnd 67469272Schristos || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) 67569272Schristos || ((flags & EV_BACKCMD) != 0 67647112Sbostic && (cmdentry.cmdtype != CMDBUILTIN 67747112Sbostic || cmdentry.u.index == DOTCMD 67869272Schristos || cmdentry.u.index == EVALCMD))) { 67947112Sbostic jp = makejob(cmd, 1); 68047112Sbostic mode = cmd->ncmd.backgnd; 68147112Sbostic if (flags & EV_BACKCMD) { 68247112Sbostic mode = FORK_NOJOB; 68347112Sbostic if (pipe(pip) < 0) 68447112Sbostic error("Pipe call failed"); 68547112Sbostic } 68647112Sbostic if (forkshell(jp, cmd, mode) != 0) 68747112Sbostic goto parent; /* at end of routine */ 68847112Sbostic if (flags & EV_BACKCMD) { 68947112Sbostic FORCEINTON; 69047112Sbostic close(pip[0]); 69147112Sbostic if (pip[1] != 1) { 69247112Sbostic close(1); 69347112Sbostic copyfd(pip[1], 1); 69447112Sbostic close(pip[1]); 69547112Sbostic } 69647112Sbostic } 69747112Sbostic flags |= EV_EXIT; 69847112Sbostic } 69947112Sbostic 70047112Sbostic /* This is the child process if a fork occurred. */ 70147112Sbostic /* Execute the command. */ 70247112Sbostic if (cmdentry.cmdtype == CMDFUNCTION) { 70347112Sbostic trputs("Shell function: "); trargs(argv); 70447112Sbostic redirect(cmd->ncmd.redirect, REDIR_PUSH); 70547112Sbostic saveparam = shellparam; 70647112Sbostic shellparam.malloc = 0; 70747112Sbostic shellparam.nparam = argc - 1; 70847112Sbostic shellparam.p = argv + 1; 70947112Sbostic shellparam.optnext = NULL; 71047112Sbostic INTOFF; 71147112Sbostic savelocalvars = localvars; 71247112Sbostic localvars = NULL; 71347112Sbostic INTON; 71447112Sbostic if (setjmp(jmploc.loc)) { 71547112Sbostic if (exception == EXSHELLPROC) 71647112Sbostic freeparam((struct shparam *)&saveparam); 71747112Sbostic else { 71847112Sbostic freeparam(&shellparam); 71947112Sbostic shellparam = saveparam; 72047112Sbostic } 72147112Sbostic poplocalvars(); 72247112Sbostic localvars = savelocalvars; 72347112Sbostic handler = savehandler; 72447112Sbostic longjmp(handler->loc, 1); 72547112Sbostic } 72647112Sbostic savehandler = handler; 72747112Sbostic handler = &jmploc; 72847112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 72947112Sbostic mklocal(sp->text); 73047112Sbostic funcnest++; 73147112Sbostic evaltree(cmdentry.u.func, 0); 73247112Sbostic funcnest--; 73347112Sbostic INTOFF; 73447112Sbostic poplocalvars(); 73547112Sbostic localvars = savelocalvars; 73647112Sbostic freeparam(&shellparam); 73747112Sbostic shellparam = saveparam; 73847112Sbostic handler = savehandler; 73947112Sbostic popredir(); 74047112Sbostic INTON; 74147112Sbostic if (evalskip == SKIPFUNC) { 74247112Sbostic evalskip = 0; 74347112Sbostic skipcount = 0; 74447112Sbostic } 74547112Sbostic if (flags & EV_EXIT) 74647112Sbostic exitshell(exitstatus); 74747112Sbostic } else if (cmdentry.cmdtype == CMDBUILTIN) { 74847112Sbostic trputs("builtin command: "); trargs(argv); 74947112Sbostic mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 75047112Sbostic if (flags == EV_BACKCMD) { 75147112Sbostic memout.nleft = 0; 75247112Sbostic memout.nextc = memout.buf; 75347112Sbostic memout.bufsize = 64; 75447112Sbostic mode |= REDIR_BACKQ; 75547112Sbostic } 75647112Sbostic redirect(cmd->ncmd.redirect, mode); 75747112Sbostic savecmdname = commandname; 75847112Sbostic cmdenviron = varlist.list; 75947112Sbostic e = -1; 76047112Sbostic if (setjmp(jmploc.loc)) { 76147112Sbostic e = exception; 76247112Sbostic exitstatus = (e == EXINT)? SIGINT+128 : 2; 76347112Sbostic goto cmddone; 76447112Sbostic } 76547112Sbostic savehandler = handler; 76647112Sbostic handler = &jmploc; 76747112Sbostic commandname = argv[0]; 76847112Sbostic argptr = argv + 1; 76947112Sbostic optptr = NULL; /* initialize nextopt */ 77047112Sbostic exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 77147112Sbostic flushall(); 77247112Sbostic cmddone: 77347112Sbostic out1 = &output; 77447112Sbostic out2 = &errout; 77547112Sbostic freestdout(); 77647112Sbostic if (e != EXSHELLPROC) { 77747112Sbostic commandname = savecmdname; 77847112Sbostic if (flags & EV_EXIT) { 77947112Sbostic exitshell(exitstatus); 78047112Sbostic } 78147112Sbostic } 78247112Sbostic handler = savehandler; 78347112Sbostic if (e != -1) { 78447112Sbostic if (e != EXERROR || cmdentry.u.index == BLTINCMD 78547112Sbostic || cmdentry.u.index == DOTCMD 78647112Sbostic || cmdentry.u.index == EVALCMD 78769272Schristos #ifndef NO_HISTORY 78855245Smarc || cmdentry.u.index == HISTCMD 78969272Schristos #endif 79047112Sbostic || cmdentry.u.index == EXECCMD) 79147112Sbostic exraise(e); 79247112Sbostic FORCEINTON; 79347112Sbostic } 79447112Sbostic if (cmdentry.u.index != EXECCMD) 79547112Sbostic popredir(); 79647112Sbostic if (flags == EV_BACKCMD) { 79747112Sbostic backcmd->buf = memout.buf; 79847112Sbostic backcmd->nleft = memout.nextc - memout.buf; 79947112Sbostic memout.buf = NULL; 80047112Sbostic } 80147112Sbostic } else { 80247112Sbostic trputs("normal command: "); trargs(argv); 80347112Sbostic clearredir(); 80447112Sbostic redirect(cmd->ncmd.redirect, 0); 80547112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 80647112Sbostic setvareq(sp->text, VEXPORT|VSTACK); 80747112Sbostic envp = environment(); 80869272Schristos shellexec(argv, envp, pathval(), cmdentry.u.index); 80947112Sbostic /*NOTREACHED*/ 81047112Sbostic } 81147112Sbostic goto out; 81247112Sbostic 81347112Sbostic parent: /* parent process gets here (if we forked) */ 81447112Sbostic if (mode == 0) { /* argument to fork */ 81547112Sbostic INTOFF; 81647112Sbostic exitstatus = waitforjob(jp); 81747112Sbostic INTON; 81847112Sbostic } else if (mode == 2) { 81947112Sbostic backcmd->fd = pip[0]; 82047112Sbostic close(pip[1]); 82147112Sbostic backcmd->jp = jp; 82247112Sbostic } 82347112Sbostic 82447112Sbostic out: 82547112Sbostic if (lastarg) 82647112Sbostic setvar("_", lastarg, 0); 82747112Sbostic popstackmark(&smark); 82847112Sbostic } 82947112Sbostic 83047112Sbostic 83147112Sbostic 83247112Sbostic /* 83347112Sbostic * Search for a command. This is called before we fork so that the 83447112Sbostic * location of the command will be available in the parent as well as 83547112Sbostic * the child. The check for "goodname" is an overly conservative 83647112Sbostic * check that the name will not be subject to expansion. 83747112Sbostic */ 83847112Sbostic 83947112Sbostic STATIC void 84047112Sbostic prehash(n) 84147112Sbostic union node *n; 84269391Schristos { 84347112Sbostic struct cmdentry entry; 84447112Sbostic 84569272Schristos if (n->type == NCMD && n->ncmd.args) 84669272Schristos if (goodname(n->ncmd.args->narg.text)) 84769272Schristos find_command(n->ncmd.args->narg.text, &entry, 0); 84847112Sbostic } 84947112Sbostic 85047112Sbostic 85147112Sbostic 85247112Sbostic /* 85347112Sbostic * Builtin commands. Builtin commands whose functions are closely 85447112Sbostic * tied to evaluation are implemented here. 85547112Sbostic */ 85647112Sbostic 85747112Sbostic /* 85847112Sbostic * No command given, or a bltin command with no arguments. Set the 85947112Sbostic * specified variables. 86047112Sbostic */ 86147112Sbostic 86269272Schristos int 86369272Schristos bltincmd(argc, argv) 86469272Schristos int argc; 86569272Schristos char **argv; 86669272Schristos { 86747112Sbostic listsetvar(cmdenviron); 86869391Schristos /* 86969391Schristos * Preserve exitstatus of a previous possible redirection 87069391Schristos * as POSIX mandates 87169391Schristos */ 87269391Schristos return exitstatus; 87347112Sbostic } 87447112Sbostic 87547112Sbostic 87647112Sbostic /* 87747112Sbostic * Handle break and continue commands. Break, continue, and return are 87847112Sbostic * all handled by setting the evalskip flag. The evaluation routines 87947112Sbostic * above all check this flag, and if it is set they start skipping 88047112Sbostic * commands rather than executing them. The variable skipcount is 88147112Sbostic * the number of loops to break/continue, or the number of function 88247112Sbostic * levels to return. (The latter is always 1.) It should probably 88347112Sbostic * be an error to break out of more loops than exist, but it isn't 88447112Sbostic * in the standard shell so we don't make it one here. 88547112Sbostic */ 88647112Sbostic 88769272Schristos int 88869272Schristos breakcmd(argc, argv) 88969272Schristos int argc; 89069272Schristos char **argv; 89169272Schristos { 89247112Sbostic int n; 89347112Sbostic 89447112Sbostic n = 1; 89547112Sbostic if (argc > 1) 89647112Sbostic n = number(argv[1]); 89747112Sbostic if (n > loopnest) 89847112Sbostic n = loopnest; 89947112Sbostic if (n > 0) { 90047112Sbostic evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 90147112Sbostic skipcount = n; 90247112Sbostic } 90347112Sbostic return 0; 90447112Sbostic } 90547112Sbostic 90647112Sbostic 90747112Sbostic /* 90847112Sbostic * The return command. 90947112Sbostic */ 91047112Sbostic 91169272Schristos int 91269272Schristos returncmd(argc, argv) 91369272Schristos int argc; 91469272Schristos char **argv; 91569272Schristos { 91647112Sbostic int ret; 91747112Sbostic 91847112Sbostic ret = exitstatus; 91947112Sbostic if (argc > 1) 92047112Sbostic ret = number(argv[1]); 92147112Sbostic if (funcnest) { 92247112Sbostic evalskip = SKIPFUNC; 92347112Sbostic skipcount = 1; 92447112Sbostic } 92547112Sbostic return ret; 92647112Sbostic } 92747112Sbostic 92847112Sbostic 92969272Schristos int 93069272Schristos falsecmd(argc, argv) 93169272Schristos int argc; 93269272Schristos char **argv; 93369272Schristos { 93468916Sbostic return 1; 93568916Sbostic } 93668916Sbostic 93768916Sbostic 93869272Schristos int 93969272Schristos truecmd(argc, argv) 94069272Schristos int argc; 94169272Schristos char **argv; 94269272Schristos { 94347112Sbostic return 0; 94447112Sbostic } 94547112Sbostic 94647112Sbostic 94769272Schristos int 94869272Schristos execcmd(argc, argv) 94969272Schristos int argc; 95069272Schristos char **argv; 95169272Schristos { 95247112Sbostic if (argc > 1) { 95369272Schristos struct strlist *sp; 95469272Schristos 95547112Sbostic iflag = 0; /* exit on error */ 95655245Smarc mflag = 0; 95755245Smarc optschanged(); 95869272Schristos for (sp = cmdenviron; sp ; sp = sp->next) 95969272Schristos setvareq(sp->text, VEXPORT|VSTACK); 96047112Sbostic shellexec(argv + 1, environment(), pathval(), 0); 96147112Sbostic 96247112Sbostic } 96347112Sbostic return 0; 96447112Sbostic } 965