147112Sbostic /*- 2*60703Sbostic * Copyright (c) 1993 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 * 8*60703Sbostic * %sccs.include.redist.c% 947112Sbostic */ 1047112Sbostic 1147112Sbostic #ifndef lint 12*60703Sbostic static char sccsid[] = "@(#)eval.c 5.9 (Berkeley) 05/31/93"; 1347112Sbostic #endif /* not lint */ 1447112Sbostic 1547112Sbostic /* 1647112Sbostic * Evaluate a command. 1747112Sbostic */ 1847112Sbostic 1947112Sbostic #include "shell.h" 2047112Sbostic #include "nodes.h" 2147112Sbostic #include "syntax.h" 2247112Sbostic #include "expand.h" 2347112Sbostic #include "parser.h" 2447112Sbostic #include "jobs.h" 2547112Sbostic #include "eval.h" 2647112Sbostic #include "builtins.h" 2747112Sbostic #include "options.h" 2847112Sbostic #include "exec.h" 2947112Sbostic #include "redir.h" 3047112Sbostic #include "input.h" 3147112Sbostic #include "output.h" 3247112Sbostic #include "trap.h" 3347112Sbostic #include "var.h" 3447112Sbostic #include "memalloc.h" 3547112Sbostic #include "error.h" 3647112Sbostic #include "mystring.h" 3755245Smarc #include "myhistedit.h" 3847112Sbostic #include <signal.h> 3947112Sbostic 4047112Sbostic 4147112Sbostic /* flags in argument to evaltree */ 4247112Sbostic #define EV_EXIT 01 /* exit after evaluating tree */ 4347112Sbostic #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 4447112Sbostic #define EV_BACKCMD 04 /* command executing within back quotes */ 4547112Sbostic 4647112Sbostic 4747112Sbostic /* reasons for skipping commands (see comment on breakcmd routine) */ 4847112Sbostic #define SKIPBREAK 1 4947112Sbostic #define SKIPCONT 2 5047112Sbostic #define SKIPFUNC 3 5147112Sbostic 5247112Sbostic MKINIT int evalskip; /* set if we are skipping commands */ 5347112Sbostic STATIC int skipcount; /* number of levels to skip */ 5447112Sbostic MKINIT int loopnest; /* current loop nesting level */ 5547112Sbostic int funcnest; /* depth of function calls */ 5647112Sbostic 5747112Sbostic 5847112Sbostic char *commandname; 5947112Sbostic struct strlist *cmdenviron; 6047112Sbostic int exitstatus; /* exit status of last command */ 6147112Sbostic 6247112Sbostic 6347112Sbostic #ifdef __STDC__ 6447112Sbostic STATIC void evalloop(union node *); 6547112Sbostic STATIC void evalfor(union node *); 6647112Sbostic STATIC void evalcase(union node *, int); 6747112Sbostic STATIC void evalsubshell(union node *, int); 6847112Sbostic STATIC void expredir(union node *); 6947112Sbostic STATIC void evalpipe(union node *); 7047112Sbostic STATIC void evalcommand(union node *, int, struct backcmd *); 7147112Sbostic STATIC void prehash(union node *); 7247112Sbostic #else 7347112Sbostic STATIC void evalloop(); 7447112Sbostic STATIC void evalfor(); 7547112Sbostic STATIC void evalcase(); 7647112Sbostic STATIC void evalsubshell(); 7747112Sbostic STATIC void expredir(); 7847112Sbostic STATIC void evalpipe(); 7947112Sbostic STATIC void evalcommand(); 8047112Sbostic STATIC void prehash(); 8147112Sbostic #endif 8247112Sbostic 8347112Sbostic 8447112Sbostic 8547112Sbostic /* 8647112Sbostic * Called to reset things after an exception. 8747112Sbostic */ 8847112Sbostic 8947112Sbostic #ifdef mkinit 9047112Sbostic INCLUDE "eval.h" 9147112Sbostic 9247112Sbostic RESET { 9347112Sbostic evalskip = 0; 9447112Sbostic loopnest = 0; 9547112Sbostic funcnest = 0; 9647112Sbostic } 9747112Sbostic 9847112Sbostic SHELLPROC { 9947112Sbostic exitstatus = 0; 10047112Sbostic } 10147112Sbostic #endif 10247112Sbostic 10347112Sbostic 10447112Sbostic 10547112Sbostic /* 10647292Smarc * The eval commmand. 10747112Sbostic */ 10847112Sbostic 10947292Smarc evalcmd(argc, argv) 11047292Smarc char **argv; 11147292Smarc { 11247292Smarc char *p; 11347292Smarc char *concat; 11447292Smarc char **ap; 11547112Sbostic 11647292Smarc if (argc > 1) { 11747292Smarc p = argv[1]; 11847292Smarc if (argc > 2) { 11947292Smarc STARTSTACKSTR(concat); 12047292Smarc ap = argv + 2; 12147292Smarc for (;;) { 12247292Smarc while (*p) 12347292Smarc STPUTC(*p++, concat); 12447292Smarc if ((p = *ap++) == NULL) 12547292Smarc break; 12647292Smarc STPUTC(' ', concat); 12747292Smarc } 12847292Smarc STPUTC('\0', concat); 12947292Smarc p = grabstackstr(concat); 13047292Smarc } 13147292Smarc evalstring(p); 13247292Smarc } 13347292Smarc return exitstatus; 13447112Sbostic } 13547112Sbostic 13647112Sbostic 13747112Sbostic /* 13847112Sbostic * Execute a command or commands contained in a string. 13947112Sbostic */ 14047112Sbostic 14147112Sbostic void 14247112Sbostic evalstring(s) 14347112Sbostic char *s; 14447112Sbostic { 14547112Sbostic union node *n; 14647112Sbostic struct stackmark smark; 14747112Sbostic 14847112Sbostic setstackmark(&smark); 14947112Sbostic setinputstring(s, 1); 15047112Sbostic while ((n = parsecmd(0)) != NEOF) { 15147112Sbostic evaltree(n, 0); 15247112Sbostic popstackmark(&smark); 15347112Sbostic } 15447112Sbostic popfile(); 15547112Sbostic popstackmark(&smark); 15647112Sbostic } 15747112Sbostic 15847112Sbostic 15947112Sbostic 16047112Sbostic /* 16147112Sbostic * Evaluate a parse tree. The value is left in the global variable 16247112Sbostic * exitstatus. 16347112Sbostic */ 16447112Sbostic 16547112Sbostic void 16647112Sbostic evaltree(n, flags) 16747112Sbostic union node *n; 16847112Sbostic { 16947112Sbostic if (n == NULL) { 17047112Sbostic TRACE(("evaltree(NULL) called\n")); 17155245Smarc exitstatus = 0; 17255245Smarc goto out; 17347112Sbostic } 17455245Smarc displayhist = 1; /* show history substitutions done with fc */ 17547112Sbostic TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type)); 17647112Sbostic switch (n->type) { 17747112Sbostic case NSEMI: 17847112Sbostic evaltree(n->nbinary.ch1, 0); 17947112Sbostic if (evalskip) 18047112Sbostic goto out; 18147112Sbostic evaltree(n->nbinary.ch2, flags); 18247112Sbostic break; 18347112Sbostic case NAND: 18447112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 18547112Sbostic if (evalskip || exitstatus != 0) 18647112Sbostic goto out; 18747112Sbostic evaltree(n->nbinary.ch2, flags); 18847112Sbostic break; 18947112Sbostic case NOR: 19047112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 19147112Sbostic if (evalskip || exitstatus == 0) 19247112Sbostic goto out; 19347112Sbostic evaltree(n->nbinary.ch2, flags); 19447112Sbostic break; 19547112Sbostic case NREDIR: 19647112Sbostic expredir(n->nredir.redirect); 19747112Sbostic redirect(n->nredir.redirect, REDIR_PUSH); 19847112Sbostic evaltree(n->nredir.n, flags); 19947112Sbostic popredir(); 20047112Sbostic break; 20147112Sbostic case NSUBSHELL: 20247112Sbostic evalsubshell(n, flags); 20347112Sbostic break; 20447112Sbostic case NBACKGND: 20547112Sbostic evalsubshell(n, flags); 20647112Sbostic break; 20747982Smarc case NIF: { 20847982Smarc int status = 0; 20947982Smarc 21047112Sbostic evaltree(n->nif.test, EV_TESTED); 21147112Sbostic if (evalskip) 21247112Sbostic goto out; 21347112Sbostic if (exitstatus == 0) { 21447112Sbostic evaltree(n->nif.ifpart, flags); 21547982Smarc status = exitstatus; 21647112Sbostic } else if (n->nif.elsepart) { 21747112Sbostic evaltree(n->nif.elsepart, flags); 21847982Smarc status = exitstatus; 21947112Sbostic } 22047982Smarc exitstatus = status; 22147112Sbostic break; 22247982Smarc } 22347112Sbostic case NWHILE: 22447112Sbostic case NUNTIL: 22547112Sbostic evalloop(n); 22647112Sbostic break; 22747112Sbostic case NFOR: 22847112Sbostic evalfor(n); 22947112Sbostic break; 23047112Sbostic case NCASE: 23147112Sbostic evalcase(n, flags); 23247112Sbostic break; 23347112Sbostic case NDEFUN: 23447112Sbostic defun(n->narg.text, n->narg.next); 23547112Sbostic exitstatus = 0; 23647112Sbostic break; 23753175Smarc case NNOT: 23853175Smarc evaltree(n->nnot.com, EV_TESTED); 23953175Smarc exitstatus = !exitstatus; 24053175Smarc break; 24153175Smarc 24247112Sbostic case NPIPE: 24347112Sbostic evalpipe(n); 24447112Sbostic break; 24547112Sbostic case NCMD: 24647112Sbostic evalcommand(n, flags, (struct backcmd *)NULL); 24747112Sbostic break; 24847112Sbostic default: 24947112Sbostic out1fmt("Node type = %d\n", n->type); 25047112Sbostic flushout(&output); 25147112Sbostic break; 25247112Sbostic } 25347112Sbostic out: 25447112Sbostic if (pendingsigs) 25547112Sbostic dotrap(); 25647112Sbostic if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 25747112Sbostic exitshell(exitstatus); 25847112Sbostic } 25947112Sbostic 26047112Sbostic 26147112Sbostic STATIC void 26247112Sbostic evalloop(n) 26347112Sbostic union node *n; 26447112Sbostic { 26547112Sbostic int status; 26647112Sbostic 26747112Sbostic loopnest++; 26847112Sbostic status = 0; 26947112Sbostic for (;;) { 27047112Sbostic evaltree(n->nbinary.ch1, EV_TESTED); 27147112Sbostic if (evalskip) { 27247112Sbostic skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 27347112Sbostic evalskip = 0; 27447112Sbostic continue; 27547112Sbostic } 27647112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 27747112Sbostic evalskip = 0; 27847112Sbostic break; 27947112Sbostic } 28047112Sbostic if (n->type == NWHILE) { 28147112Sbostic if (exitstatus != 0) 28247112Sbostic break; 28347112Sbostic } else { 28447112Sbostic if (exitstatus == 0) 28547112Sbostic break; 28647112Sbostic } 28747112Sbostic evaltree(n->nbinary.ch2, 0); 28847112Sbostic status = exitstatus; 28947112Sbostic if (evalskip) 29047112Sbostic goto skipping; 29147112Sbostic } 29247112Sbostic loopnest--; 29347112Sbostic exitstatus = status; 29447112Sbostic } 29547112Sbostic 29647112Sbostic 29747112Sbostic 29847112Sbostic STATIC void 29947112Sbostic evalfor(n) 30047112Sbostic union node *n; 30147112Sbostic { 30247112Sbostic struct arglist arglist; 30347112Sbostic union node *argp; 30447112Sbostic struct strlist *sp; 30547112Sbostic struct stackmark smark; 30647112Sbostic 30747112Sbostic setstackmark(&smark); 30847112Sbostic arglist.lastp = &arglist.list; 30947112Sbostic for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 31053298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 31147112Sbostic if (evalskip) 31247112Sbostic goto out; 31347112Sbostic } 31447112Sbostic *arglist.lastp = NULL; 31547112Sbostic 31647112Sbostic exitstatus = 0; 31747112Sbostic loopnest++; 31847112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 31947112Sbostic setvar(n->nfor.var, sp->text, 0); 32047112Sbostic evaltree(n->nfor.body, 0); 32147112Sbostic if (evalskip) { 32247112Sbostic if (evalskip == SKIPCONT && --skipcount <= 0) { 32347112Sbostic evalskip = 0; 32447112Sbostic continue; 32547112Sbostic } 32647112Sbostic if (evalskip == SKIPBREAK && --skipcount <= 0) 32747112Sbostic evalskip = 0; 32847112Sbostic break; 32947112Sbostic } 33047112Sbostic } 33147112Sbostic loopnest--; 33247112Sbostic out: 33347112Sbostic popstackmark(&smark); 33447112Sbostic } 33547112Sbostic 33647112Sbostic 33747112Sbostic 33847112Sbostic STATIC void 33947112Sbostic evalcase(n, flags) 34047112Sbostic union node *n; 34147112Sbostic { 34247112Sbostic union node *cp; 34347112Sbostic union node *patp; 34447112Sbostic struct arglist arglist; 34547112Sbostic struct stackmark smark; 34647112Sbostic 34747112Sbostic setstackmark(&smark); 34847112Sbostic arglist.lastp = &arglist.list; 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; 37347112Sbostic { 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; 40147112Sbostic { 40247112Sbostic register union node *redir; 40347112Sbostic 40447112Sbostic for (redir = n ; redir ; redir = redir->nfile.next) { 40547112Sbostic if (redir->type == NFROM 40647112Sbostic || redir->type == NTO 40747112Sbostic || redir->type == NAPPEND) { 40847112Sbostic struct arglist fn; 40947112Sbostic fn.lastp = &fn.list; 41053298Smarc expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 41147112Sbostic redir->nfile.expfname = fn.list->text; 41247112Sbostic } 41347112Sbostic } 41447112Sbostic } 41547112Sbostic 41647112Sbostic 41747112Sbostic 41847112Sbostic /* 41947112Sbostic * Evaluate a pipeline. All the processes in the pipeline are children 42047112Sbostic * of the process creating the pipeline. (This differs from some versions 42147112Sbostic * of the shell, which make the last process in a pipeline the parent 42247112Sbostic * of all the rest.) 42347112Sbostic */ 42447112Sbostic 42547112Sbostic STATIC void 42647112Sbostic evalpipe(n) 42747112Sbostic union node *n; 42847112Sbostic { 42947112Sbostic struct job *jp; 43047112Sbostic struct nodelist *lp; 43147112Sbostic int pipelen; 43247112Sbostic int prevfd; 43347112Sbostic int pip[2]; 43447112Sbostic 43547112Sbostic TRACE(("evalpipe(0x%x) called\n", (int)n)); 43647112Sbostic pipelen = 0; 43747112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 43847112Sbostic pipelen++; 43947112Sbostic INTOFF; 44047112Sbostic jp = makejob(n, pipelen); 44147112Sbostic prevfd = -1; 44247112Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 44347112Sbostic prehash(lp->n); 44447112Sbostic pip[1] = -1; 44547112Sbostic if (lp->next) { 44647112Sbostic if (pipe(pip) < 0) { 44747112Sbostic close(prevfd); 44847112Sbostic error("Pipe call failed"); 44947112Sbostic } 45047112Sbostic } 45147112Sbostic if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 45247112Sbostic INTON; 45347112Sbostic if (prevfd > 0) { 45447112Sbostic close(0); 45547112Sbostic copyfd(prevfd, 0); 45647112Sbostic close(prevfd); 45747112Sbostic } 45847112Sbostic if (pip[1] >= 0) { 45947112Sbostic close(pip[0]); 46047112Sbostic if (pip[1] != 1) { 46147112Sbostic close(1); 46247112Sbostic copyfd(pip[1], 1); 46347112Sbostic close(pip[1]); 46447112Sbostic } 46547112Sbostic } 46647112Sbostic evaltree(lp->n, EV_EXIT); 46747112Sbostic } 46847112Sbostic if (prevfd >= 0) 46947112Sbostic close(prevfd); 47047112Sbostic prevfd = pip[0]; 47147112Sbostic close(pip[1]); 47247112Sbostic } 47347112Sbostic INTON; 47447112Sbostic if (n->npipe.backgnd == 0) { 47547112Sbostic INTOFF; 47647112Sbostic exitstatus = waitforjob(jp); 47747112Sbostic TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 47847112Sbostic INTON; 47947112Sbostic } 48047112Sbostic } 48147112Sbostic 48247112Sbostic 48347112Sbostic 48447112Sbostic /* 48547112Sbostic * Execute a command inside back quotes. If it's a builtin command, we 48647112Sbostic * want to save its output in a block obtained from malloc. Otherwise 48747112Sbostic * we fork off a subprocess and get the output of the command via a pipe. 48847112Sbostic * Should be called with interrupts off. 48947112Sbostic */ 49047112Sbostic 49147112Sbostic void 49247112Sbostic evalbackcmd(n, result) 49347112Sbostic union node *n; 49447112Sbostic struct backcmd *result; 49547112Sbostic { 49647112Sbostic int pip[2]; 49747112Sbostic struct job *jp; 49847112Sbostic struct stackmark smark; /* unnecessary */ 49947112Sbostic 50047112Sbostic setstackmark(&smark); 50147112Sbostic result->fd = -1; 50247112Sbostic result->buf = NULL; 50347112Sbostic result->nleft = 0; 50447112Sbostic result->jp = NULL; 50555798Smarc exitstatus = 0; 50655798Smarc if (n == NULL) 50755798Smarc goto out; 50847112Sbostic if (n->type == NCMD) { 50947112Sbostic evalcommand(n, EV_BACKCMD, result); 51047112Sbostic } else { 51147112Sbostic if (pipe(pip) < 0) 51247112Sbostic error("Pipe call failed"); 51347112Sbostic jp = makejob(n, 1); 51447112Sbostic if (forkshell(jp, n, FORK_NOJOB) == 0) { 51547112Sbostic FORCEINTON; 51647112Sbostic close(pip[0]); 51747112Sbostic if (pip[1] != 1) { 51847112Sbostic close(1); 51947112Sbostic copyfd(pip[1], 1); 52047112Sbostic close(pip[1]); 52147112Sbostic } 52247112Sbostic evaltree(n, EV_EXIT); 52347112Sbostic } 52447112Sbostic close(pip[1]); 52547112Sbostic result->fd = pip[0]; 52647112Sbostic result->jp = jp; 52747112Sbostic } 52855798Smarc out: 52947112Sbostic popstackmark(&smark); 53047112Sbostic TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 53147112Sbostic result->fd, result->buf, result->nleft, result->jp)); 53247112Sbostic } 53347112Sbostic 53447112Sbostic 53547112Sbostic 53647112Sbostic /* 53747112Sbostic * Execute a simple command. 53847112Sbostic */ 53947112Sbostic 54047112Sbostic STATIC void 54147112Sbostic evalcommand(cmd, flags, backcmd) 54247112Sbostic union node *cmd; 54347112Sbostic struct backcmd *backcmd; 54447112Sbostic { 54547112Sbostic struct stackmark smark; 54647112Sbostic union node *argp; 54747112Sbostic struct arglist arglist; 54847112Sbostic struct arglist varlist; 54947112Sbostic char **argv; 55047112Sbostic int argc; 55147112Sbostic char **envp; 55247112Sbostic int varflag; 55347112Sbostic struct strlist *sp; 55447112Sbostic register char *p; 55547112Sbostic int mode; 55647112Sbostic int pip[2]; 55747112Sbostic struct cmdentry cmdentry; 55847112Sbostic struct job *jp; 55947112Sbostic struct jmploc jmploc; 56047112Sbostic struct jmploc *volatile savehandler; 56147112Sbostic char *volatile savecmdname; 56247112Sbostic volatile struct shparam saveparam; 56347112Sbostic struct localvar *volatile savelocalvars; 56447112Sbostic volatile int e; 56547112Sbostic char *lastarg; 56647112Sbostic 56747112Sbostic /* First expand the arguments. */ 56847112Sbostic TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags)); 56947112Sbostic setstackmark(&smark); 57047112Sbostic arglist.lastp = &arglist.list; 57147112Sbostic varlist.lastp = &varlist.list; 57247112Sbostic varflag = 1; 57347112Sbostic for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 57447112Sbostic p = argp->narg.text; 57547112Sbostic if (varflag && is_name(*p)) { 57647112Sbostic do { 57747112Sbostic p++; 57847112Sbostic } while (is_in_name(*p)); 57947112Sbostic if (*p == '=') { 58053298Smarc expandarg(argp, &varlist, EXP_VARTILDE); 58147112Sbostic continue; 58247112Sbostic } 58347112Sbostic } 58453298Smarc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 58547112Sbostic varflag = 0; 58647112Sbostic } 58747112Sbostic *arglist.lastp = NULL; 58847112Sbostic *varlist.lastp = NULL; 58947112Sbostic expredir(cmd->ncmd.redirect); 59047112Sbostic argc = 0; 59147112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) 59247112Sbostic argc++; 59347112Sbostic argv = stalloc(sizeof (char *) * (argc + 1)); 59455245Smarc 59553298Smarc for (sp = arglist.list ; sp ; sp = sp->next) { 59653298Smarc TRACE(("evalcommand arg: %s\n", sp->text)); 59747112Sbostic *argv++ = sp->text; 59853298Smarc } 59947112Sbostic *argv = NULL; 60047112Sbostic lastarg = NULL; 60147112Sbostic if (iflag && funcnest == 0 && argc > 0) 60247112Sbostic lastarg = argv[-1]; 60347112Sbostic argv -= argc; 60447112Sbostic 60547112Sbostic /* Print the command if xflag is set. */ 60647112Sbostic if (xflag) { 60747112Sbostic outc('+', &errout); 60847112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) { 60947112Sbostic outc(' ', &errout); 61047112Sbostic out2str(sp->text); 61147112Sbostic } 61247112Sbostic for (sp = arglist.list ; sp ; sp = sp->next) { 61347112Sbostic outc(' ', &errout); 61447112Sbostic out2str(sp->text); 61547112Sbostic } 61647112Sbostic outc('\n', &errout); 61747112Sbostic flushout(&errout); 61847112Sbostic } 61947112Sbostic 62047112Sbostic /* Now locate the command. */ 62147112Sbostic if (argc == 0) { 62247112Sbostic cmdentry.cmdtype = CMDBUILTIN; 62347112Sbostic cmdentry.u.index = BLTINCMD; 62447112Sbostic } else { 62547112Sbostic find_command(argv[0], &cmdentry, 1); 62647112Sbostic if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 62747112Sbostic exitstatus = 2; 62847112Sbostic flushout(&errout); 62947112Sbostic return; 63047112Sbostic } 63147112Sbostic /* implement the bltin builtin here */ 63247112Sbostic if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 63347112Sbostic for (;;) { 63447112Sbostic argv++; 63547112Sbostic if (--argc == 0) 63647112Sbostic break; 63747112Sbostic if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 63847112Sbostic outfmt(&errout, "%s: not found\n", *argv); 63947112Sbostic exitstatus = 2; 64047112Sbostic flushout(&errout); 64147112Sbostic return; 64247112Sbostic } 64347112Sbostic if (cmdentry.u.index != BLTINCMD) 64447112Sbostic break; 64547112Sbostic } 64647112Sbostic } 64747112Sbostic } 64847112Sbostic 64947112Sbostic /* Fork off a child process if necessary. */ 65047112Sbostic if (cmd->ncmd.backgnd 65147112Sbostic || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0 65247112Sbostic || (flags & EV_BACKCMD) != 0 65347112Sbostic && (cmdentry.cmdtype != CMDBUILTIN 65447112Sbostic || cmdentry.u.index == DOTCMD 65547112Sbostic || cmdentry.u.index == EVALCMD)) { 65647112Sbostic jp = makejob(cmd, 1); 65747112Sbostic mode = cmd->ncmd.backgnd; 65847112Sbostic if (flags & EV_BACKCMD) { 65947112Sbostic mode = FORK_NOJOB; 66047112Sbostic if (pipe(pip) < 0) 66147112Sbostic error("Pipe call failed"); 66247112Sbostic } 66347112Sbostic if (forkshell(jp, cmd, mode) != 0) 66447112Sbostic goto parent; /* at end of routine */ 66547112Sbostic if (flags & EV_BACKCMD) { 66647112Sbostic FORCEINTON; 66747112Sbostic close(pip[0]); 66847112Sbostic if (pip[1] != 1) { 66947112Sbostic close(1); 67047112Sbostic copyfd(pip[1], 1); 67147112Sbostic close(pip[1]); 67247112Sbostic } 67347112Sbostic } 67447112Sbostic flags |= EV_EXIT; 67547112Sbostic } 67647112Sbostic 67747112Sbostic /* This is the child process if a fork occurred. */ 67847112Sbostic /* Execute the command. */ 67947112Sbostic if (cmdentry.cmdtype == CMDFUNCTION) { 68047112Sbostic trputs("Shell function: "); trargs(argv); 68147112Sbostic redirect(cmd->ncmd.redirect, REDIR_PUSH); 68247112Sbostic saveparam = shellparam; 68347112Sbostic shellparam.malloc = 0; 68447112Sbostic shellparam.nparam = argc - 1; 68547112Sbostic shellparam.p = argv + 1; 68647112Sbostic shellparam.optnext = NULL; 68747112Sbostic INTOFF; 68847112Sbostic savelocalvars = localvars; 68947112Sbostic localvars = NULL; 69047112Sbostic INTON; 69147112Sbostic if (setjmp(jmploc.loc)) { 69247112Sbostic if (exception == EXSHELLPROC) 69347112Sbostic freeparam((struct shparam *)&saveparam); 69447112Sbostic else { 69547112Sbostic freeparam(&shellparam); 69647112Sbostic shellparam = saveparam; 69747112Sbostic } 69847112Sbostic poplocalvars(); 69947112Sbostic localvars = savelocalvars; 70047112Sbostic handler = savehandler; 70147112Sbostic longjmp(handler->loc, 1); 70247112Sbostic } 70347112Sbostic savehandler = handler; 70447112Sbostic handler = &jmploc; 70547112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 70647112Sbostic mklocal(sp->text); 70747112Sbostic funcnest++; 70847112Sbostic evaltree(cmdentry.u.func, 0); 70947112Sbostic funcnest--; 71047112Sbostic INTOFF; 71147112Sbostic poplocalvars(); 71247112Sbostic localvars = savelocalvars; 71347112Sbostic freeparam(&shellparam); 71447112Sbostic shellparam = saveparam; 71547112Sbostic handler = savehandler; 71647112Sbostic popredir(); 71747112Sbostic INTON; 71847112Sbostic if (evalskip == SKIPFUNC) { 71947112Sbostic evalskip = 0; 72047112Sbostic skipcount = 0; 72147112Sbostic } 72247112Sbostic if (flags & EV_EXIT) 72347112Sbostic exitshell(exitstatus); 72447112Sbostic } else if (cmdentry.cmdtype == CMDBUILTIN) { 72547112Sbostic trputs("builtin command: "); trargs(argv); 72647112Sbostic mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 72747112Sbostic if (flags == EV_BACKCMD) { 72847112Sbostic memout.nleft = 0; 72947112Sbostic memout.nextc = memout.buf; 73047112Sbostic memout.bufsize = 64; 73147112Sbostic mode |= REDIR_BACKQ; 73247112Sbostic } 73347112Sbostic redirect(cmd->ncmd.redirect, mode); 73447112Sbostic savecmdname = commandname; 73547112Sbostic cmdenviron = varlist.list; 73647112Sbostic e = -1; 73747112Sbostic if (setjmp(jmploc.loc)) { 73847112Sbostic e = exception; 73947112Sbostic exitstatus = (e == EXINT)? SIGINT+128 : 2; 74047112Sbostic goto cmddone; 74147112Sbostic } 74247112Sbostic savehandler = handler; 74347112Sbostic handler = &jmploc; 74447112Sbostic commandname = argv[0]; 74547112Sbostic argptr = argv + 1; 74647112Sbostic optptr = NULL; /* initialize nextopt */ 74747112Sbostic exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 74847112Sbostic flushall(); 74947112Sbostic cmddone: 75047112Sbostic out1 = &output; 75147112Sbostic out2 = &errout; 75247112Sbostic freestdout(); 75347112Sbostic if (e != EXSHELLPROC) { 75447112Sbostic commandname = savecmdname; 75547112Sbostic if (flags & EV_EXIT) { 75647112Sbostic exitshell(exitstatus); 75747112Sbostic } 75847112Sbostic } 75947112Sbostic handler = savehandler; 76047112Sbostic if (e != -1) { 76147112Sbostic if (e != EXERROR || cmdentry.u.index == BLTINCMD 76247112Sbostic || cmdentry.u.index == DOTCMD 76347112Sbostic || cmdentry.u.index == EVALCMD 76455245Smarc || cmdentry.u.index == HISTCMD 76547112Sbostic || cmdentry.u.index == EXECCMD) 76647112Sbostic exraise(e); 76747112Sbostic FORCEINTON; 76847112Sbostic } 76947112Sbostic if (cmdentry.u.index != EXECCMD) 77047112Sbostic popredir(); 77147112Sbostic if (flags == EV_BACKCMD) { 77247112Sbostic backcmd->buf = memout.buf; 77347112Sbostic backcmd->nleft = memout.nextc - memout.buf; 77447112Sbostic memout.buf = NULL; 77547112Sbostic } 77647112Sbostic } else { 77747112Sbostic trputs("normal command: "); trargs(argv); 77847112Sbostic clearredir(); 77947112Sbostic redirect(cmd->ncmd.redirect, 0); 78047112Sbostic if (varlist.list) { 78147112Sbostic p = stalloc(strlen(pathval()) + 1); 78247112Sbostic scopy(pathval(), p); 78347112Sbostic } else { 78447112Sbostic p = pathval(); 78547112Sbostic } 78647112Sbostic for (sp = varlist.list ; sp ; sp = sp->next) 78747112Sbostic setvareq(sp->text, VEXPORT|VSTACK); 78847112Sbostic envp = environment(); 78947112Sbostic shellexec(argv, envp, p, cmdentry.u.index); 79047112Sbostic /*NOTREACHED*/ 79147112Sbostic } 79247112Sbostic goto out; 79347112Sbostic 79447112Sbostic parent: /* parent process gets here (if we forked) */ 79547112Sbostic if (mode == 0) { /* argument to fork */ 79647112Sbostic INTOFF; 79747112Sbostic exitstatus = waitforjob(jp); 79847112Sbostic INTON; 79947112Sbostic } else if (mode == 2) { 80047112Sbostic backcmd->fd = pip[0]; 80147112Sbostic close(pip[1]); 80247112Sbostic backcmd->jp = jp; 80347112Sbostic } 80447112Sbostic 80547112Sbostic out: 80647112Sbostic if (lastarg) 80747112Sbostic setvar("_", lastarg, 0); 80847112Sbostic popstackmark(&smark); 80947112Sbostic } 81047112Sbostic 81147112Sbostic 81247112Sbostic 81347112Sbostic /* 81447112Sbostic * Search for a command. This is called before we fork so that the 81547112Sbostic * location of the command will be available in the parent as well as 81647112Sbostic * the child. The check for "goodname" is an overly conservative 81747112Sbostic * check that the name will not be subject to expansion. 81847112Sbostic */ 81947112Sbostic 82047112Sbostic STATIC void 82147112Sbostic prehash(n) 82247112Sbostic union node *n; 82347112Sbostic { 82447112Sbostic struct cmdentry entry; 82547112Sbostic 82647112Sbostic if (n->type == NCMD && goodname(n->ncmd.args->narg.text)) 82747112Sbostic find_command(n->ncmd.args->narg.text, &entry, 0); 82847112Sbostic } 82947112Sbostic 83047112Sbostic 83147112Sbostic 83247112Sbostic /* 83347112Sbostic * Builtin commands. Builtin commands whose functions are closely 83447112Sbostic * tied to evaluation are implemented here. 83547112Sbostic */ 83647112Sbostic 83747112Sbostic /* 83847112Sbostic * No command given, or a bltin command with no arguments. Set the 83947112Sbostic * specified variables. 84047112Sbostic */ 84147112Sbostic 84247112Sbostic bltincmd(argc, argv) char **argv; { 84347112Sbostic listsetvar(cmdenviron); 84447112Sbostic return exitstatus; 84547112Sbostic } 84647112Sbostic 84747112Sbostic 84847112Sbostic /* 84947112Sbostic * Handle break and continue commands. Break, continue, and return are 85047112Sbostic * all handled by setting the evalskip flag. The evaluation routines 85147112Sbostic * above all check this flag, and if it is set they start skipping 85247112Sbostic * commands rather than executing them. The variable skipcount is 85347112Sbostic * the number of loops to break/continue, or the number of function 85447112Sbostic * levels to return. (The latter is always 1.) It should probably 85547112Sbostic * be an error to break out of more loops than exist, but it isn't 85647112Sbostic * in the standard shell so we don't make it one here. 85747112Sbostic */ 85847112Sbostic 85947112Sbostic breakcmd(argc, argv) char **argv; { 86047112Sbostic int n; 86147112Sbostic 86247112Sbostic n = 1; 86347112Sbostic if (argc > 1) 86447112Sbostic n = number(argv[1]); 86547112Sbostic if (n > loopnest) 86647112Sbostic n = loopnest; 86747112Sbostic if (n > 0) { 86847112Sbostic evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 86947112Sbostic skipcount = n; 87047112Sbostic } 87147112Sbostic return 0; 87247112Sbostic } 87347112Sbostic 87447112Sbostic 87547112Sbostic /* 87647112Sbostic * The return command. 87747112Sbostic */ 87847112Sbostic 87947112Sbostic returncmd(argc, argv) char **argv; { 88047112Sbostic int ret; 88147112Sbostic 88247112Sbostic ret = exitstatus; 88347112Sbostic if (argc > 1) 88447112Sbostic ret = number(argv[1]); 88547112Sbostic if (funcnest) { 88647112Sbostic evalskip = SKIPFUNC; 88747112Sbostic skipcount = 1; 88847112Sbostic } 88947112Sbostic return ret; 89047112Sbostic } 89147112Sbostic 89247112Sbostic 89347112Sbostic truecmd(argc, argv) char **argv; { 89447112Sbostic return 0; 89547112Sbostic } 89647112Sbostic 89747112Sbostic 89847112Sbostic execcmd(argc, argv) char **argv; { 89947112Sbostic if (argc > 1) { 90047112Sbostic iflag = 0; /* exit on error */ 90155245Smarc mflag = 0; 90255245Smarc optschanged(); 90347112Sbostic shellexec(argv + 1, environment(), pathval(), 0); 90447112Sbostic 90547112Sbostic } 90647112Sbostic return 0; 90747112Sbostic } 908