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