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