eval.c revision 201343
14Srgrimes/*- 24Srgrimes * Copyright (c) 1993 34Srgrimes * The Regents of the University of California. All rights reserved. 44Srgrimes * 54Srgrimes * This code is derived from software contributed to Berkeley by 64Srgrimes * Kenneth Almquist. 74Srgrimes * 84Srgrimes * Redistribution and use in source and binary forms, with or without 94Srgrimes * modification, are permitted provided that the following conditions 104Srgrimes * are met: 114Srgrimes * 1. Redistributions of source code must retain the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer. 134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer in the 154Srgrimes * documentation and/or other materials provided with the distribution. 164Srgrimes * 4. Neither the name of the University nor the names of its contributors 174Srgrimes * may be used to endorse or promote products derived from this software 184Srgrimes * without specific prior written permission. 194Srgrimes * 204Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304Srgrimes * SUCH DAMAGE. 314Srgrimes */ 324Srgrimes 334Srgrimes#ifndef lint 344Srgrimes#if 0 354Srgrimesstatic char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 36619Srgrimes#endif 3748888Sbde#endif /* not lint */ 384Srgrimes#include <sys/cdefs.h> 394Srgrimes__FBSDID("$FreeBSD: head/bin/sh/eval.c 201343 2009-12-31 16:13:33Z jilles $"); 403185Ssos 4119173Sbde#include <paths.h> 4219173Sbde#include <signal.h> 4319173Sbde#include <stdlib.h> 4419173Sbde#include <unistd.h> 453185Ssos#include <sys/resource.h> 463185Ssos#include <sys/wait.h> /* For WIFSIGNALED(status) */ 473185Ssos#include <errno.h> 483185Ssos 492913Sache/* 502913Sache * Evaluate a command. 5116299Spst */ 5233929Sphk 5313228Swollman#include "shell.h" 542056Swollman#include "nodes.h" 552056Swollman#include "syntax.h" 562056Swollman#include "expand.h" 572056Swollman#include "parser.h" 5831253Sbde#include "jobs.h" 5931253Sbde#include "eval.h" 6031253Sbde#include "builtins.h" 6115508Sbde#include "options.h" 6215508Sbde#include "exec.h" 634180Sbde#include "redir.h" 6415508Sbde#include "input.h" 6515508Sbde#include "output.h" 6615508Sbde#include "trap.h" 6730805Sbde#include "var.h" 682056Swollman#include "memalloc.h" 6926309Speter#include "error.h" 7028551Sbde#include "show.h" 7132054Sphk#include "mystring.h" 7247588Sbde#ifndef NO_HISTORY 7334617Sphk#include "myhistedit.h" 7434617Sphk#endif 7534617Sphk 7634617Sphk 7730805Sbdeint evalskip; /* set if we are skipping commands */ 7830805SbdeSTATIC int skipcount; /* number of levels to skip */ 7930805SbdeMKINIT int loopnest; /* current loop nesting level */ 8028921Sfsmpint funcnest; /* depth of function calls */ 8126949SfsmpSTATIC int builtin_flags; /* evalcommand flags for builtins */ 8228921Sfsmp 8332054Sphk 8415508Sbdechar *commandname; 852056Swollmanstruct strlist *cmdenviron; 862056Swollmanint exitstatus; /* exit status of last command */ 8747642Sdfrint oexitstatus; /* saved exit status */ 882056Swollman 894Srgrimes 9045897SpeterSTATIC void evalloop(union node *, int); 9128487SfsmpSTATIC void evalfor(union node *, int); 9228921SfsmpSTATIC void evalcase(union node *, int); 9329000SfsmpSTATIC void evalsubshell(union node *, int); 9429000SfsmpSTATIC void expredir(union node *); 9534058SteggeSTATIC void evalpipe(union node *); 9634571SteggeSTATIC void evalcommand(union node *, int, struct backcmd *); 9734571SteggeSTATIC void prehash(union node *); 9834058Stegge 9934058Stegge 10034571Stegge/* 10134571Stegge * Called to reset things after an exception. 10234571Stegge */ 10328921Sfsmp 10428921Sfsmp#ifdef mkinit 1052873SbdeINCLUDE "eval.h" 1062873Sbde 1072873SbdeRESET { 1082873Sbde evalskip = 0; 1092873Sbde loopnest = 0; 1102913Sache funcnest = 0; 1112873Sbde} 11215508Sbde 1134SrgrimesSHELLPROC { 1144180Sbde exitstatus = 0; 1154180Sbde} 1164180Sbde#endif 1174180Sbde 1184180Sbde 1194180Sbde 1204180Sbde/* 1214180Sbde * The eval command. 1224180Sbde */ 1234180Sbde 12417236Sjoergint 12517231Sjoergevalcmd(int argc, char **argv) 12633690Sphk{ 1274180Sbde char *p; 12817231Sjoerg char *concat; 1294180Sbde char **ap; 13041787Smckay 13147588Sbde if (argc > 1) { 13215045Sache p = argv[1]; 13346847Speter if (argc > 2) { 13432052Sphk STARTSTACKSTR(concat); 13532052Sphk ap = argv + 2; 13633690Sphk for (;;) { 13733690Sphk while (*p) 13833690Sphk STPUTC(*p++, concat); 13932052Sphk if ((p = *ap++) == NULL) 14032052Sphk break; 14132005Sphk STPUTC(' ', concat); 14247592Sphk } 14341787Smckay STPUTC('\0', concat); 1441390Ssos p = grabstackstr(concat); 1454180Sbde } 1465291Sbde evalstring(p, builtin_flags & EV_TESTED); 1474180Sbde } 14819173Sbde return exitstatus; 14933690Sphk} 15033690Sphk 15133690Sphk 1524180Sbde/* 1534180Sbde * Execute a command or commands contained in a string. 1544180Sbde */ 1554180Sbde 1564180Sbdevoid 1574180Sbdeevalstring(char *s, int flags) 15819173Sbde{ 15919173Sbde union node *n; 1604180Sbde struct stackmark smark; 16115345Snate int flags_exit; 16233690Sphk 16317231Sjoerg flags_exit = flags & EV_EXIT; 16417231Sjoerg flags &= ~EV_EXIT; 16517236Sjoerg setstackmark(&smark); 16617236Sjoerg setinputstring(s, 1); 16717236Sjoerg while ((n = parsecmd(0)) != NEOF) { 16817236Sjoerg if (n != NULL) { 16917231Sjoerg if (flags_exit && preadateof()) 17017231Sjoerg evaltree(n, flags | EV_EXIT); 17117231Sjoerg else 17219173Sbde evaltree(n, flags); 17333690Sphk } 1744180Sbde popstackmark(&smark); 17536719Sphk } 17636719Sphk popfile(); 17721783Sbde popstackmark(&smark); 17817353Sbde if (flags_exit) 17940610Sphk exitshell(exitstatus); 18033690Sphk} 18136741Sphk 18236198Sphk 18333690Sphk/* 18433690Sphk * Evaluate a parse tree. The value is left in the global variable 18533690Sphk * exitstatus. 18633690Sphk */ 18733690Sphk 18840610Sphkvoid 18933690Sphkevaltree(union node *n, int flags) 19040610Sphk{ 19133690Sphk int do_etest; 19236741Sphk 19336198Sphk do_etest = 0; 19433690Sphk if (n == NULL) { 19533690Sphk TRACE(("evaltree(NULL) called\n")); 19633690Sphk exitstatus = 0; 19733690Sphk goto out; 19833690Sphk } 19940610Sphk#ifndef NO_HISTORY 20033690Sphk displayhist = 1; /* show history substitutions done with fc */ 20112724Sphk#endif 2023185Ssos TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type)); 2032074Swollman switch (n->type) { 20439503Sbde case NSEMI: 20547588Sbde evaltree(n->nbinary.ch1, flags & ~EV_EXIT); 20647588Sbde if (evalskip) 20739503Sbde goto out; 20847588Sbde evaltree(n->nbinary.ch2, flags); 20939503Sbde break; 21039503Sbde case NAND: 21139503Sbde evaltree(n->nbinary.ch1, EV_TESTED); 21247588Sbde if (evalskip || exitstatus != 0) { 21347588Sbde goto out; 21439503Sbde } 2151549Srgrimes evaltree(n->nbinary.ch2, flags); 2161442Ssos break; 21717236Sjoerg case NOR: 21817231Sjoerg evaltree(n->nbinary.ch1, EV_TESTED); 2198448Sbde if (evalskip || exitstatus == 0) 2201442Ssos goto out; 22117236Sjoerg evaltree(n->nbinary.ch2, flags); 22217231Sjoerg break; 2234180Sbde case NREDIR: 2244180Sbde expredir(n->nredir.redirect); 22533309Sbde redirect(n->nredir.redirect, REDIR_PUSH); 2261549Srgrimes evaltree(n->nredir.n, flags); 2278448Sbde popredir(); 2281390Ssos break; 2291442Ssos case NSUBSHELL: 23017236Sjoerg evalsubshell(n, flags); 23117231Sjoerg do_etest = !(flags & EV_TESTED); 2328448Sbde break; 2334180Sbde case NBACKGND: 23429000Sfsmp evalsubshell(n, flags); 2354180Sbde break; 2364180Sbde case NIF: { 2374180Sbde evaltree(n->nif.test, EV_TESTED); 23829000Sfsmp if (evalskip) 2394180Sbde goto out; 2401442Ssos if (exitstatus == 0) 24117231Sjoerg evaltree(n->nif.ifpart, flags); 2421442Ssos else if (n->nif.elsepart) 24317236Sjoerg evaltree(n->nif.elsepart, flags); 24417231Sjoerg else 2454180Sbde exitstatus = 0; 2464180Sbde break; 24733309Sbde } 24834961Sphk case NWHILE: 24933309Sbde case NUNTIL: 25034961Sphk evalloop(n, flags & ~EV_EXIT); 25134961Sphk break; 25234961Sphk case NFOR: 25334961Sphk evalfor(n, flags & ~EV_EXIT); 25434961Sphk break; 25533309Sbde case NCASE: 25633309Sbde evalcase(n, flags); 25733309Sbde break; 25833309Sbde case NDEFUN: 25933309Sbde defun(n->narg.text, n->narg.next); 26034961Sphk exitstatus = 0; 2611549Srgrimes break; 2628448Sbde case NNOT: 2635291Sbde evaltree(n->nnot.com, EV_TESTED); 26429000Sfsmp exitstatus = !exitstatus; 2654180Sbde break; 2664180Sbde 2674180Sbde case NPIPE: 2684180Sbde evalpipe(n); 26929000Sfsmp do_etest = !(flags & EV_TESTED); 2704180Sbde break; 27117231Sjoerg case NCMD: 27217231Sjoerg evalcommand(n, flags, (struct backcmd *)NULL); 2731442Ssos do_etest = !(flags & EV_TESTED); 2741442Ssos break; 2751442Ssos default: 2761390Ssos out1fmt("Node type = %d\n", n->type); 2771390Ssos flushout(&output); 27817231Sjoerg break; 27917236Sjoerg } 28017231Sjoergout: 2811390Ssos if (pendingsigs) 2824180Sbde dotrap(); 2831390Ssos if ((flags & EV_EXIT) || (eflag && exitstatus != 0 && do_etest)) 28417231Sjoerg exitshell(exitstatus); 28517231Sjoerg} 28617231Sjoerg 28717231Sjoerg 28836810SphkSTATIC void 28933690Sphkevalloop(union node *n, int flags) 29017231Sjoerg{ 29117231Sjoerg int status; 29217236Sjoerg 29317236Sjoerg loopnest++; 29417236Sjoerg status = 0; 29517231Sjoerg for (;;) { 29617236Sjoerg evaltree(n->nbinary.ch1, EV_TESTED); 29717236Sjoerg if (evalskip) { 29817236Sjoergskipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 29917236Sjoerg evalskip = 0; 30017236Sjoerg continue; 30117236Sjoerg } 30217236Sjoerg if (evalskip == SKIPBREAK && --skipcount <= 0) 30317236Sjoerg evalskip = 0; 30417236Sjoerg break; 30517236Sjoerg } 30617236Sjoerg if (n->type == NWHILE) { 30717236Sjoerg if (exitstatus != 0) 30817236Sjoerg break; 30917236Sjoerg } else { 31017231Sjoerg if (exitstatus == 0) 3111442Ssos break; 31217231Sjoerg } 31317231Sjoerg evaltree(n->nbinary.ch2, flags); 3141390Ssos status = exitstatus; 3151390Ssos if (evalskip) 3161390Ssos goto skipping; 3171390Ssos } 3181390Ssos loopnest--; 31917231Sjoerg exitstatus = status; 32017231Sjoerg} 32117231Sjoerg 32217231Sjoerg 32317236Sjoerg 32417236SjoergSTATIC void 32517236Sjoergevalfor(union node *n, int flags) 32617236Sjoerg{ 32717236Sjoerg struct arglist arglist; 32817236Sjoerg union node *argp; 32917236Sjoerg struct strlist *sp; 33017236Sjoerg struct stackmark smark; 33117236Sjoerg 33217236Sjoerg setstackmark(&smark); 33317231Sjoerg arglist.lastp = &arglist.list; 3341390Ssos for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 3351390Ssos oexitstatus = exitstatus; 3361390Ssos expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 3371390Ssos if (evalskip) 3381390Ssos goto out; 33917231Sjoerg } 34017231Sjoerg *arglist.lastp = NULL; 34117236Sjoerg 34217236Sjoerg exitstatus = 0; 34317236Sjoerg loopnest++; 34417231Sjoerg for (sp = arglist.list ; sp ; sp = sp->next) { 34517236Sjoerg setvar(n->nfor.var, sp->text, 0); 34617236Sjoerg evaltree(n->nfor.body, flags); 34717236Sjoerg if (evalskip) { 34817236Sjoerg if (evalskip == SKIPCONT && --skipcount <= 0) { 34917236Sjoerg evalskip = 0; 35017236Sjoerg continue; 35117236Sjoerg } 35217231Sjoerg if (evalskip == SKIPBREAK && --skipcount <= 0) 35317231Sjoerg evalskip = 0; 3541390Ssos break; 3551390Ssos } 3561390Ssos } 3571390Ssos loopnest--; 3581390Ssosout: 35917231Sjoerg popstackmark(&smark); 36017231Sjoerg} 36117231Sjoerg 36217231Sjoerg 36317236Sjoerg 36417231SjoergSTATIC void 3651390Ssosevalcase(union node *n, int flags) 3661390Ssos{ 3673185Ssos union node *cp; 3683185Ssos union node *patp; 3693185Ssos struct arglist arglist; 3703185Ssos struct stackmark smark; 3713185Ssos 3723185Ssos setstackmark(&smark); 3733185Ssos arglist.lastp = &arglist.list; 3743185Ssos oexitstatus = exitstatus; 3753185Ssos exitstatus = 0; 3763185Ssos expandarg(n->ncase.expr, &arglist, EXP_TILDE); 3773185Ssos for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 3783185Ssos for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 37924676Smckay if (casematch(patp, arglist.list->text)) { 38024676Smckay if (evalskip == 0) { 38124676Smckay evaltree(cp->nclist.body, flags); 38224676Smckay } 38324676Smckay goto out; 38424676Smckay } 38524676Smckay } 38624676Smckay } 3873185Ssosout: 38812724Sphk popstackmark(&smark); 3893185Ssos} 3903185Ssos 39124676Smckay 3923185Ssos 3933185Ssos/* 3941390Ssos * Kick off a subshell to evaluate a tree. 39518297Sbde */ 3965291Sbde 39718297SbdeSTATIC void 39818297Sbdeevalsubshell(union node *n, int flags) 39918297Sbde{ 4003185Ssos struct job *jp; 4015291Sbde int backgnd = (n->type == NBACKGND); 4025291Sbde 4035291Sbde expredir(n->nredir.redirect); 4045291Sbde if ((!backgnd && flags & EV_EXIT && !have_traps()) || 4053185Ssos forkshell(jp = makejob(n, 1), n, backgnd) == 0) { 40618297Sbde if (backgnd) 4073185Ssos flags &=~ EV_TESTED; 4081390Ssos redirect(n->nredir.redirect, 0); 40910268Sbde evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 4101390Ssos } else if (! backgnd) { 41116428Sbde INTOFF; 4121390Ssos exitstatus = waitforjob(jp, (int *)NULL); 4131390Ssos INTON; 41416428Sbde } 41529000Sfsmp} 41616428Sbde 41716428Sbde 41819173Sbde 41916428Sbde/* 4201390Ssos * Compute the names of the files in a redirection list. 4211390Ssos */ 42216428Sbde 42328921SfsmpSTATIC void 42416428Sbdeexpredir(union node *n) 4251390Ssos{ 4261390Ssos union node *redir; 4271390Ssos 4282017Swollman for (redir = n ; redir ; redir = redir->nfile.next) { 4291390Ssos struct arglist fn; 43015508Sbde fn.lastp = &fn.list; 4311390Ssos oexitstatus = exitstatus; 4321390Ssos switch (redir->type) { 4331390Ssos case NFROM: 4341390Ssos case NTO: 4351390Ssos case NFROMTO: 43622106Sbde case NAPPEND: 4371390Ssos case NCLOBBER: 4381390Ssos expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 4391390Ssos redir->nfile.expfname = fn.list->text; 4401390Ssos break; 4411390Ssos case NFROMFD: 4421390Ssos case NTOFD: 4431390Ssos if (redir->ndup.vname) { 4441390Ssos expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); 4451390Ssos fixredir(redir, fn.list->text, 1); 4461390Ssos } 4471390Ssos break; 4481390Ssos } 4491390Ssos } 4501390Ssos} 4511390Ssos 4521390Ssos 45321783Sbde 45421783Sbde/* 45521783Sbde * Evaluate a pipeline. All the processes in the pipeline are children 45621783Sbde * of the process creating the pipeline. (This differs from some versions 45721783Sbde * of the shell, which make the last process in a pipeline the parent 45821783Sbde * of all the rest.) 45921783Sbde */ 4601390Ssos 4611390SsosSTATIC void 4621390Ssosevalpipe(union node *n) 4631390Ssos{ 4641390Ssos struct job *jp; 4651390Ssos struct nodelist *lp; 46610268Sbde int pipelen; 46722106Sbde int prevfd; 4681390Ssos int pip[2]; 46915508Sbde 4701390Ssos TRACE(("evalpipe(%p) called\n", (void *)n)); 4711390Ssos pipelen = 0; 47222106Sbde for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 47322106Sbde pipelen++; 47422106Sbde INTOFF; 47522106Sbde jp = makejob(n, pipelen); 47622106Sbde prevfd = -1; 47722106Sbde for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 47822106Sbde prehash(lp->n); 47922106Sbde pip[1] = -1; 48022106Sbde if (lp->next) { 48122106Sbde if (pipe(pip) < 0) { 48222106Sbde close(prevfd); 48322106Sbde error("Pipe call failed: %s", strerror(errno)); 48422106Sbde } 48522106Sbde } 48622106Sbde if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 48722106Sbde INTON; 48822106Sbde if (prevfd > 0) { 48922106Sbde dup2(prevfd, 0); 49022106Sbde close(prevfd); 4911390Ssos } 4921390Ssos if (pip[1] >= 0) { 49310268Sbde if (!(prevfd >= 0 && pip[0] == 0)) 4941390Ssos close(pip[0]); 4951390Ssos if (pip[1] != 1) { 4961390Ssos dup2(pip[1], 1); 49721783Sbde close(pip[1]); 4981390Ssos } 49921783Sbde } 50021783Sbde evaltree(lp->n, EV_EXIT); 50121783Sbde } 50221783Sbde if (prevfd >= 0) 50321783Sbde close(prevfd); 50421783Sbde prevfd = pip[0]; 50521783Sbde close(pip[1]); 50621783Sbde } 50721783Sbde INTON; 50821783Sbde if (n->npipe.backgnd == 0) { 50921783Sbde INTOFF; 51021783Sbde exitstatus = waitforjob(jp, (int *)NULL); 5111390Ssos TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 5121390Ssos INTON; 5131390Ssos } 5141390Ssos} 5151390Ssos 5161390Ssos 5171390Ssos 5181390Ssos/* 5191390Ssos * Execute a command inside back quotes. If it's a builtin command, we 5203185Ssos * want to save its output in a block obtained from malloc. Otherwise 5211390Ssos * we fork off a subprocess and get the output of the command via a pipe. 5221390Ssos * Should be called with interrupts off. 5231390Ssos */ 5241390Ssos 5251390Ssosvoid 5261390Ssosevalbackcmd(union node *n, struct backcmd *result) 5278876Srgrimes{ 5281390Ssos int pip[2]; 5291390Ssos struct job *jp; 53017231Sjoerg struct stackmark smark; /* unnecessary */ 5311390Ssos 5328876Srgrimes setstackmark(&smark); 53317231Sjoerg result->fd = -1; 53417231Sjoerg result->buf = NULL; 53517231Sjoerg result->nleft = 0; 53617231Sjoerg result->jp = NULL; 53717231Sjoerg if (n == NULL) { 53829000Sfsmp exitstatus = 0; 5391390Ssos goto out; 5401390Ssos } 54129000Sfsmp if (n->type == NCMD) { 5421390Ssos exitstatus = oexitstatus; 54317231Sjoerg evalcommand(n, EV_BACKCMD, result); 54417231Sjoerg } else { 5451390Ssos exitstatus = 0; 5462873Sbde if (pipe(pip) < 0) 5471390Ssos error("Pipe call failed: %s", strerror(errno)); 54817231Sjoerg jp = makejob(n, 1); 54917231Sjoerg if (forkshell(jp, n, FORK_NOJOB) == 0) { 5501390Ssos FORCEINTON; 5511390Ssos close(pip[0]); 5522913Sache if (pip[1] != 1) { 5532913Sache dup2(pip[1], 1); 5542913Sache close(pip[1]); 5552913Sache } 55614943Sbde evaltree(n, EV_EXIT); 55714943Sbde } 55814943Sbde close(pip[1]); 55914943Sbde result->fd = pip[0]; 56014943Sbde result->jp = jp; 56114943Sbde } 56214943Sbdeout: 56314943Sbde popstackmark(&smark); 56414943Sbde TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n", 56514943Sbde result->fd, result->buf, result->nleft, result->jp)); 56614943Sbde} 56714943Sbde 56814943Sbde 56913445Sphk 5705291Sbde/* 5712913Sache * Execute a simple command. 57233309Sbde */ 5735291Sbde 57433309SbdeSTATIC void 5755291Sbdeevalcommand(union node *cmd, int flags, struct backcmd *backcmd) 57633309Sbde{ 5772913Sache struct stackmark smark; 5782913Sache union node *argp; 57913445Sphk struct arglist arglist; 5802913Sache struct arglist varlist; 5812913Sache char **argv; 58213445Sphk int argc; 5832913Sache char **envp; 5842913Sache int varflag; 58515508Sbde struct strlist *sp; 58615508Sbde int mode; 58715508Sbde int pip[2]; 58848160Sgreen struct cmdentry cmdentry; 58915508Sbde struct job *jp; 59015508Sbde struct jmploc jmploc; 59115508Sbde struct jmploc *savehandler; 59223393Sbde char *savecmdname; 59323393Sbde struct shparam saveparam; 59415508Sbde struct localvar *savelocalvars; 59515508Sbde struct parsefile *savetopfile; 59615508Sbde volatile int e; 59715508Sbde char *lastarg; 59815508Sbde int realstatus; 59915508Sbde int do_clearcmdentry; 60015508Sbde 60115508Sbde /* First expand the arguments. */ 60215508Sbde TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags)); 60315508Sbde setstackmark(&smark); 60415508Sbde arglist.lastp = &arglist.list; 60515508Sbde varlist.lastp = &varlist.list; 60615508Sbde varflag = 1; 60715508Sbde do_clearcmdentry = 0; 60815508Sbde oexitstatus = exitstatus; 60915508Sbde exitstatus = 0; 61015508Sbde for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 61115508Sbde char *p = argp->narg.text; 61215508Sbde if (varflag && is_name(*p)) { 61315508Sbde do { 61415508Sbde p++; 61515508Sbde } while (is_in_name(*p)); 61615508Sbde if (*p == '=') { 61715508Sbde expandarg(argp, &varlist, EXP_VARTILDE); 61815508Sbde continue; 61915508Sbde } 62015508Sbde } 62115508Sbde expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 62215508Sbde varflag = 0; 62315508Sbde } 62415508Sbde *arglist.lastp = NULL; 62515508Sbde *varlist.lastp = NULL; 62632054Sphk expredir(cmd->ncmd.redirect); 62748160Sgreen argc = 0; 62848266Speter for (sp = arglist.list ; sp ; sp = sp->next) 62948266Speter argc++; 63015508Sbde argv = stalloc(sizeof (char *) * (argc + 1)); 63115508Sbde 63215508Sbde for (sp = arglist.list ; sp ; sp = sp->next) { 63315508Sbde TRACE(("evalcommand arg: %s\n", sp->text)); 63415508Sbde *argv++ = sp->text; 63515508Sbde } 63615508Sbde *argv = NULL; 63715508Sbde lastarg = NULL; 63815508Sbde if (iflag && funcnest == 0 && argc > 0) 63915508Sbde lastarg = argv[-1]; 64015508Sbde argv -= argc; 64115508Sbde 64215508Sbde /* Print the command if xflag is set. */ 64315508Sbde if (xflag) { 64415508Sbde char sep = 0; 64515508Sbde const char *p; 64615508Sbde out2str(ps4val()); 64715508Sbde for (sp = varlist.list ; sp ; sp = sp->next) { 64815508Sbde if (sep != 0) 64915508Sbde outc(' ', &errout); 65015508Sbde p = sp->text; 65115508Sbde while (*p != '=' && *p != '\0') 65215508Sbde out2c(*p++); 65315508Sbde if (*p != '\0') { 65415508Sbde out2c(*p++); 65515508Sbde out2qstr(p); 65615508Sbde } 65715508Sbde sep = ' '; 65815508Sbde } 65915508Sbde for (sp = arglist.list ; sp ; sp = sp->next) { 66015508Sbde if (sep != 0) 66115508Sbde outc(' ', &errout); 66215508Sbde /* Disambiguate command looking like assignment. */ 66333690Sphk if (sp == arglist.list && 66448160Sgreen strchr(sp->text, '=') != NULL && 66533690Sphk strchr(sp->text, '\'') == NULL) { 66633690Sphk out2c('\''); 66733690Sphk out2str(sp->text); 66832005Sphk out2c('\''); 66933929Sphk } else 67015508Sbde out2qstr(sp->text); 67115508Sbde sep = ' '; 67215508Sbde } 67315508Sbde outc('\n', &errout); 67423393Sbde flushout(&errout); 67523393Sbde } 67623393Sbde 67715508Sbde /* Now locate the command. */ 67815508Sbde if (argc == 0) { 67915508Sbde /* Variable assignment(s) without command */ 68015508Sbde cmdentry.cmdtype = CMDBUILTIN; 68115508Sbde cmdentry.u.index = BLTINCMD; 68215508Sbde cmdentry.special = 1; 68316874Sbde } else { 68433309Sbde static const char PATH[] = "PATH="; 68515508Sbde char *path = pathval(); 68615508Sbde 68729000Sfsmp /* 68815508Sbde * Modify the command lookup path, if a PATH= assignment 68933309Sbde * is present 69033309Sbde */ 69133309Sbde for (sp = varlist.list ; sp ; sp = sp->next) 69233309Sbde if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { 69333309Sbde path = sp->text + sizeof(PATH) - 1; 69433309Sbde /* 69533309Sbde * On `PATH=... command`, we need to make 69628921Sfsmp * sure that the command isn't using the 69715508Sbde * non-updated hash table of the outer PATH 69815508Sbde * setting and we need to make sure that 69915508Sbde * the hash table isn't filled with items 7005291Sbde * from the temporary setting. 70133690Sphk * 7025291Sbde * It would be better to forbit using and 7035291Sbde * updating the table while this command 7041390Ssos * runs, by the command finding mechanism 7058876Srgrimes * is heavily integrated with hash handling, 706798Swollman * so we just delete the hash before and after 70715508Sbde * the command runs. Partly deleting like 70815508Sbde * changepatch() does doesn't seem worth the 70932054Sphk * bookinging effort, since most such runs add 71032054Sphk * directories in front of the new PATH. 71132054Sphk */ 71232054Sphk clearcmdentry(0); 71332054Sphk do_clearcmdentry = 1; 71415508Sbde } 71515508Sbde 71615508Sbde find_command(argv[0], &cmdentry, 0, path); 71716874Sbde /* implement the bltin builtin here */ 71815508Sbde if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 71915508Sbde for (;;) { 72015508Sbde argv++; 72115508Sbde if (--argc == 0) 72215508Sbde break; 72318288Sbde if ((cmdentry.u.index = find_builtin(*argv, 72415508Sbde &cmdentry.special)) < 0) { 72515508Sbde outfmt(&errout, "%s: not found\n", *argv); 72615508Sbde exitstatus = 127; 72715508Sbde flushout(&errout); 72815508Sbde return; 72915508Sbde } 73015508Sbde if (cmdentry.u.index != BLTINCMD) 73115508Sbde break; 73215508Sbde } 73315508Sbde } 73415508Sbde } 73515508Sbde 73616300Spst /* Fork off a child process if necessary. */ 73719173Sbde if (cmd->ncmd.backgnd 73815508Sbde || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) 73915508Sbde && ((flags & EV_EXIT) == 0 || have_traps())) 74015508Sbde || ((flags & EV_BACKCMD) != 0 74115508Sbde && (cmdentry.cmdtype != CMDBUILTIN 74215508Sbde || cmdentry.u.index == CDCMD 74323393Sbde || cmdentry.u.index == DOTCMD 74423393Sbde || cmdentry.u.index == EVALCMD)) 74523393Sbde || (cmdentry.cmdtype == CMDBUILTIN && 74623393Sbde cmdentry.u.index == COMMANDCMD)) { 74732005Sphk jp = makejob(cmd, 1); 74815508Sbde mode = cmd->ncmd.backgnd; 74915508Sbde if (flags & EV_BACKCMD) { 75015508Sbde mode = FORK_NOJOB; 75140610Sphk if (pipe(pip) < 0) 75240610Sphk error("Pipe call failed: %s", strerror(errno)); 75315508Sbde } 75432005Sphk if (forkshell(jp, cmd, mode) != 0) 75532005Sphk goto parent; /* at end of routine */ 75616300Spst if (flags & EV_BACKCMD) { 75719173Sbde FORCEINTON; 75832005Sphk close(pip[0]); 75932005Sphk if (pip[1] != 1) { 76015508Sbde dup2(pip[1], 1); 76115508Sbde close(pip[1]); 76232054Sphk } 76315508Sbde } 76415508Sbde flags |= EV_EXIT; 76515508Sbde } 76615508Sbde 76715508Sbde /* This is the child process if a fork occurred. */ 76848160Sgreen /* Execute the command. */ 76948160Sgreen if (cmdentry.cmdtype == CMDFUNCTION) { 77015508Sbde#ifdef DEBUG 77148160Sgreen trputs("Shell function: "); trargs(argv); 77232054Sphk#endif 77323393Sbde redirect(cmd->ncmd.redirect, REDIR_PUSH); 77433690Sphk saveparam = shellparam; 77516300Spst shellparam.malloc = 0; 77615508Sbde shellparam.reset = 1; 77734617Sphk shellparam.nparam = argc - 1; 77834617Sphk shellparam.p = argv + 1; 77934617Sphk shellparam.optnext = NULL; 78034617Sphk INTOFF; 78134617Sphk savelocalvars = localvars; 78234617Sphk localvars = NULL; 78334617Sphk reffunc(cmdentry.u.func); 78434617Sphk savehandler = handler; 78534617Sphk if (setjmp(jmploc.loc)) { 78634617Sphk if (exception == EXSHELLPROC) 78734617Sphk freeparam(&saveparam); 78834617Sphk else { 78934617Sphk freeparam(&shellparam); 79034617Sphk shellparam = saveparam; 79134617Sphk } 79234617Sphk unreffunc(cmdentry.u.func); 79334617Sphk poplocalvars(); 79434617Sphk localvars = savelocalvars; 79534617Sphk funcnest--; 79634617Sphk handler = savehandler; 79734617Sphk longjmp(handler->loc, 1); 79834617Sphk } 79934617Sphk handler = &jmploc; 80034617Sphk funcnest++; 80147592Sphk INTON; 80240610Sphk for (sp = varlist.list ; sp ; sp = sp->next) 80340610Sphk mklocal(sp->text); 80433690Sphk exitstatus = oexitstatus; 80534617Sphk if (flags & EV_TESTED) 80634617Sphk evaltree(getfuncnode(cmdentry.u.func), EV_TESTED); 8074Srgrimes else 8084Srgrimes evaltree(getfuncnode(cmdentry.u.func), 0); 8092913Sache INTOFF; 81041787Smckay unreffunc(cmdentry.u.func); 81141787Smckay poplocalvars(); 8122913Sache localvars = savelocalvars; 8132913Sache freeparam(&shellparam); 8143185Ssos shellparam = saveparam; 8154Srgrimes handler = savehandler; 8162913Sache funcnest--; 8172913Sache popredir(); 8182913Sache INTON; 8192913Sache if (evalskip == SKIPFUNC) { 82033690Sphk evalskip = 0; 8214Srgrimes skipcount = 0; 82232850Sphk } 82332850Sphk if (flags & EV_EXIT) 82433690Sphk exitshell(exitstatus); 82533690Sphk } else if (cmdentry.cmdtype == CMDBUILTIN) { 82633690Sphk#ifdef DEBUG 82732850Sphk trputs("builtin command: "); trargs(argv); 82832850Sphk#endif 8291390Ssos mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 83041787Smckay if (flags == EV_BACKCMD) { 8319202Srgrimes memout.nleft = 0; 8322913Sache memout.nextc = memout.buf; 8334Srgrimes memout.bufsize = 64; 83441787Smckay mode |= REDIR_BACKQ; 83541787Smckay } 8362913Sache savecmdname = commandname; 8374Srgrimes savetopfile = getcurrentfile(); 8382913Sache cmdenviron = varlist.list; 8393355Sache e = -1; 84041787Smckay savehandler = handler; 8413355Sache if (setjmp(jmploc.loc)) { 8423355Sache e = exception; 8432913Sache exitstatus = (e == EXINT)? SIGINT+128 : 2; 8443355Sache goto cmddone; 8453355Sache } 8463355Sache handler = &jmploc; 8472913Sache redirect(cmd->ncmd.redirect, mode); 84841787Smckay if (cmdentry.special) 84941787Smckay listsetvar(cmdenviron); 85041787Smckay commandname = argv[0]; 85141787Smckay argptr = argv + 1; 8522913Sache nextopt_optptr = NULL; /* initialize nextopt */ 85341787Smckay builtin_flags = flags; 8542913Sache exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 8552913Sache flushall(); 85641787Smckaycmddone: 8572913Sache cmdenviron = NULL; 8582913Sache out1 = &output; 8592913Sache out2 = &errout; 8602913Sache freestdout(); 86141787Smckay if (e != EXSHELLPROC) { 86241787Smckay commandname = savecmdname; 8631390Ssos if (flags & EV_EXIT) { 86415054Sache exitshell(exitstatus); 8654Srgrimes } 86634961Sphk } 86733690Sphk handler = savehandler; 86833690Sphk if (e != -1) { 86933690Sphk if ((e != EXERROR && e != EXEXEC) 87033690Sphk || cmdentry.special) 87133690Sphk exraise(e); 87233690Sphk popfilesupto(savetopfile); 87333690Sphk FORCEINTON; 87433690Sphk } 8752913Sache if (cmdentry.u.index != EXECCMD) 8762913Sache popredir(); 8772913Sache if (flags == EV_BACKCMD) { 87841787Smckay backcmd->buf = memout.buf; 87941787Smckay backcmd->nleft = memout.nextc - memout.buf; 8804Srgrimes memout.buf = NULL; 8814Srgrimes } 8824Srgrimes } else { 88341787Smckay#ifdef DEBUG 8844Srgrimes trputs("normal command: "); trargs(argv); 8854180Sbde#endif 8864180Sbde redirect(cmd->ncmd.redirect, 0); 8874Srgrimes for (sp = varlist.list ; sp ; sp = sp->next) 8882913Sache setvareq(sp->text, VEXPORT|VSTACK); 88911872Sphk envp = environment(); 8904Srgrimes shellexec(argv, envp, pathval(), cmdentry.u.index); 8913366Sache /*NOTREACHED*/ 8923366Sache } 8933366Sache goto out; 8942913Sache 89534961Sphkparent: /* parent process gets here (if we forked) */ 8962913Sache if (mode == 0) { /* argument to fork */ 8974Srgrimes INTOFF; 8985291Sbde exitstatus = waitforjob(jp, &realstatus); 8992913Sache INTON; 9004Srgrimes if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 90141787Smckay evalskip = SKIPBREAK; 9021390Ssos skipcount = loopnest; 90315054Sache } 9042913Sache } else if (mode == 2) { 90513445Sphk backcmd->fd = pip[0]; 90613445Sphk close(pip[1]); 90713445Sphk backcmd->jp = jp; 9082913Sache } 90941787Smckay 9102913Sacheout: 91113350Sache if (lastarg) 91213350Sache setvar("_", lastarg, 0); 91313350Sache if (do_clearcmdentry) 91413350Sache clearcmdentry(0); 9152913Sache popstackmark(&smark); 9162913Sache} 91713453Sache 91813350Sache 91913445Sphk 9203355Sache/* 92113402Sbde * Search for a command. This is called before we fork so that the 92213402Sbde * location of the command will be available in the parent as well as 9232913Sache * the child. The check for "goodname" is an overly conservative 92413402Sbde * check that the name will not be subject to expansion. 92513402Sbde */ 92613402Sbde 92713402SbdeSTATIC void 92813402Sbdeprehash(union node *n) 92913402Sbde{ 93013402Sbde struct cmdentry entry; 93113402Sbde 93213445Sphk if (n && n->type == NCMD && n->ncmd.args) 93313445Sphk if (goodname(n->ncmd.args->narg.text)) 9342913Sache find_command(n->ncmd.args->narg.text, &entry, 0, 9355291Sbde pathval()); 93615345Snate} 9374Srgrimes 9384Srgrimes 93927560Sfsmp 9404Srgrimes/* 9415291Sbde * Builtin commands. Builtin commands whose functions are closely 9424Srgrimes * tied to evaluation are implemented here. 9435291Sbde */ 9445291Sbde 9454Srgrimes/* 9465291Sbde * No command given, or a bltin command with no arguments. 94726949Sfsmp */ 94834571Stegge 94945900Speterint 95025164Speterbltincmd(int argc __unused, char **argv __unused) 9514Srgrimes{ 95215345Snate /* 95315345Snate * Preserve exitstatus of a previous possible redirection 95415345Snate * as POSIX mandates 95515345Snate */ 95615345Snate return exitstatus; 95715345Snate} 95815345Snate 95915345Snate 96015345Snate/* 96115345Snate * Handle break and continue commands. Break, continue, and return are 96215345Snate * all handled by setting the evalskip flag. The evaluation routines 96315345Snate * above all check this flag, and if it is set they start skipping 96415345Snate * commands rather than executing them. The variable skipcount is 96515345Snate * the number of loops to break/continue, or the number of function 9664Srgrimes * levels to return. (The latter is always 1.) It should probably 9675291Sbde * be an error to break out of more loops than exist, but it isn't 96826949Sfsmp * in the standard shell so we don't make it one here. 96927563Sfsmp */ 97038888Stegge 97134571Steggeint 97234571Steggebreakcmd(int argc, char **argv) 97334571Stegge{ 97434571Stegge int n = argc > 1 ? number(argv[1]) : 1; 97534571Stegge 97634571Stegge if (n > loopnest) 97734571Stegge n = loopnest; 97834571Stegge if (n > 0) { 97934571Stegge evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 98034571Stegge skipcount = n; 98134571Stegge } 98227563Sfsmp return 0; 98327563Sfsmp} 98445897Speter 98545897Speter/* 98634571Stegge * The `command' command. 98734571Stegge */ 98827696Sfsmpint 98927563Sfsmpcommandcmd(int argc, char **argv) 99045897Speter{ 99145897Speter static char stdpath[] = _PATH_STDPATH; 9924Srgrimes struct jmploc loc, *old; 99327696Sfsmp struct strlist *sp; 99425164Speter char *path; 99526949Sfsmp int ch; 9965291Sbde int cmd = -1; 9975291Sbde 9985291Sbde for (sp = cmdenviron; sp ; sp = sp->next) 99915345Snate setvareq(sp->text, VEXPORT|VSTACK); 100015345Snate path = pathval(); 100115345Snate 100215345Snate optind = optreset = 1; 10035291Sbde opterr = 0; 10045291Sbde while ((ch = getopt(argc, argv, "pvV")) != -1) { 10055291Sbde switch (ch) { 100627520Sfsmp case 'p': 100726949Sfsmp path = stdpath; 100838888Stegge break; 100927520Sfsmp case 'v': 101027563Sfsmp cmd = TYPECMD_SMALLV; 101128487Sfsmp break; 101245897Speter case 'V': 101345897Speter cmd = TYPECMD_BIGV; 101428487Sfsmp break; 101527616Sfsmp case '?': 101627616Sfsmp default: 101727616Sfsmp error("unknown option: -%c", optopt); 10182074Swollman } 101927616Sfsmp } 102027520Sfsmp argc -= optind; 102115345Snate argv += optind; 102234571Stegge 102334571Stegge if (cmd != -1) { 102434571Stegge if (argc != 1) 102534571Stegge error("wrong number of arguments"); 102634571Stegge return typecmd_impl(2, argv - 1, cmd, path); 102734571Stegge } 102835035Stegge if (argc != 0) { 102934571Stegge old = handler; 103034571Stegge handler = &loc; 103134571Stegge if (setjmp(handler->loc) == 0) 103234571Stegge shellexec(argv, environment(), path, 0); 103334571Stegge handler = old; 103434571Stegge if (exception == EXEXEC) 103534571Stegge exit(exerrno); 103634571Stegge exraise(exception); 103745897Speter } 103834571Stegge 103934571Stegge /* 104034571Stegge * Do nothing successfully if no command was specified; 104134571Stegge * ksh also does this. 104234571Stegge */ 104334571Stegge exit(0); 104445897Speter} 104545897Speter 104634571Stegge 104734571Stegge/* 104834571Stegge * The return command. 104934571Stegge */ 105034571Stegge 105134571Steggeint 105234571Steggereturncmd(int argc, char **argv) 105334571Stegge{ 105434571Stegge int ret = argc > 1 ? number(argv[1]) : oexitstatus; 105534571Stegge 10564Srgrimes if (funcnest) { 10574Srgrimes evalskip = SKIPFUNC; 105834571Stegge skipcount = 1; 105934571Stegge } else { 106034571Stegge /* skip the rest of the file */ 106134571Stegge evalskip = SKIPFILE; 106234571Stegge skipcount = 1; 106334571Stegge } 106434571Stegge return ret; 106534571Stegge} 106634571Stegge 106734571Stegge 106834571Steggeint 106934571Steggefalsecmd(int argc __unused, char **argv __unused) 107034571Stegge{ 107134571Stegge return 1; 107234571Stegge} 107334571Stegge 107434571Stegge 107534571Steggeint 107634571Steggetruecmd(int argc __unused, char **argv __unused) 107734571Stegge{ 107834571Stegge return 0; 107934571Stegge} 108034571Stegge 108134571Stegge 108234571Steggeint 108334571Steggeexeccmd(int argc, char **argv) 108434571Stegge{ 108534571Stegge if (argc > 1) { 108634571Stegge struct strlist *sp; 108734571Stegge 108834571Stegge iflag = 0; /* exit on error */ 10894Srgrimes mflag = 0; 10901549Srgrimes optschanged(); 10911549Srgrimes for (sp = cmdenviron; sp ; sp = sp->next) 10925291Sbde setvareq(sp->text, VEXPORT|VSTACK); 10932074Swollman shellexec(argv + 1, environment(), pathval(), 0); 10945291Sbde 10952074Swollman } 10965291Sbde return 0; 10971549Srgrimes} 109815508Sbde 109915508Sbde 110015508Sbdeint 110115508Sbdetimescmd(int argc __unused, char **argv __unused) 110215508Sbde{ 110315508Sbde struct rusage ru; 110415508Sbde long shumins, shsmins, chumins, chsmins; 110515508Sbde double shusecs, shssecs, chusecs, chssecs; 110615508Sbde 110715508Sbde if (getrusage(RUSAGE_SELF, &ru) < 0) 110815508Sbde return 1; 110915508Sbde shumins = ru.ru_utime.tv_sec / 60; 111048888Sbde shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 111117353Sbde shsmins = ru.ru_stime.tv_sec / 60; 111233690Sphk shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 111315508Sbde if (getrusage(RUSAGE_CHILDREN, &ru) < 0) 111415508Sbde return 1; 111540610Sphk chumins = ru.ru_utime.tv_sec / 60; 111646054Sphk chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 111715508Sbde chsmins = ru.ru_stime.tv_sec / 60; 111815508Sbde chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 111915508Sbde out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins, 112015508Sbde shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs); 112115508Sbde return 0; 112248888Sbde} 112315508Sbde