14b88c807SRodney W. Grimes /*-
24b88c807SRodney W. Grimes * Copyright (c) 1993
34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved.
44b88c807SRodney W. Grimes *
54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by
64b88c807SRodney W. Grimes * Kenneth Almquist.
74b88c807SRodney W. Grimes *
84b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
94b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions
104b88c807SRodney W. Grimes * are met:
114b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
124b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
134b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
154b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution.
16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software
184b88c807SRodney W. Grimes * without specific prior written permission.
194b88c807SRodney W. Grimes *
204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304b88c807SRodney W. Grimes * SUCH DAMAGE.
314b88c807SRodney W. Grimes */
324b88c807SRodney W. Grimes
332babaf74STim J. Robbins #include <paths.h>
34aa9caaf6SPeter Wemm #include <signal.h>
35d1d578b2SGiorgos Keramidas #include <stdlib.h>
36aa9caaf6SPeter Wemm #include <unistd.h>
371974986aSStefan Farfeleder #include <sys/resource.h>
386c48b6cfSMartin Cracauer #include <errno.h>
39aa9caaf6SPeter Wemm
404b88c807SRodney W. Grimes /*
414b88c807SRodney W. Grimes * Evaluate a command.
424b88c807SRodney W. Grimes */
434b88c807SRodney W. Grimes
444b88c807SRodney W. Grimes #include "shell.h"
454b88c807SRodney W. Grimes #include "nodes.h"
464b88c807SRodney W. Grimes #include "syntax.h"
474b88c807SRodney W. Grimes #include "expand.h"
484b88c807SRodney W. Grimes #include "parser.h"
494b88c807SRodney W. Grimes #include "jobs.h"
504b88c807SRodney W. Grimes #include "eval.h"
514b88c807SRodney W. Grimes #include "builtins.h"
524b88c807SRodney W. Grimes #include "options.h"
534b88c807SRodney W. Grimes #include "exec.h"
544b88c807SRodney W. Grimes #include "redir.h"
554b88c807SRodney W. Grimes #include "input.h"
564b88c807SRodney W. Grimes #include "output.h"
574b88c807SRodney W. Grimes #include "trap.h"
584b88c807SRodney W. Grimes #include "var.h"
594b88c807SRodney W. Grimes #include "memalloc.h"
604b88c807SRodney W. Grimes #include "error.h"
61aa9caaf6SPeter Wemm #include "show.h"
624b88c807SRodney W. Grimes #include "mystring.h"
63aa9caaf6SPeter Wemm #ifndef NO_HISTORY
644b88c807SRodney W. Grimes #include "myhistedit.h"
65aa9caaf6SPeter Wemm #endif
664b88c807SRodney W. Grimes
674b88c807SRodney W. Grimes
68384aedabSJilles Tjoelker int evalskip; /* set if we are skipping commands */
6901a43bcfSJean-Sébastien Pédron int skipcount; /* number of levels to skip */
700bdd3871SJilles Tjoelker static int loopnest; /* current loop nesting level */
714b88c807SRodney W. Grimes int funcnest; /* depth of function calls */
72aa7b6f82SDavid E. O'Brien static int builtin_flags; /* evalcommand flags for builtins */
734b88c807SRodney W. Grimes
744b88c807SRodney W. Grimes
754b88c807SRodney W. Grimes char *commandname;
768ef0ae8aSJilles Tjoelker struct arglist *cmdenviron;
774b88c807SRodney W. Grimes int exitstatus; /* exit status of last command */
78aa9caaf6SPeter Wemm int oexitstatus; /* saved exit status */
794b88c807SRodney W. Grimes
804b88c807SRodney W. Grimes
8188328642SDavid E. O'Brien static void evalloop(union node *, int);
8288328642SDavid E. O'Brien static void evalfor(union node *, int);
8393fcb251SJilles Tjoelker static union node *evalcase(union node *);
8488328642SDavid E. O'Brien static void evalsubshell(union node *, int);
8588328642SDavid E. O'Brien static void evalredir(union node *, int);
864dc6bdd3SJilles Tjoelker static void exphere(union node *, struct arglist *);
8788328642SDavid E. O'Brien static void expredir(union node *);
8888328642SDavid E. O'Brien static void evalpipe(union node *);
89acd7984fSJilles Tjoelker static int is_valid_fast_cmdsubst(union node *n);
9088328642SDavid E. O'Brien static void evalcommand(union node *, int, struct backcmd *);
9188328642SDavid E. O'Brien static void prehash(union node *);
924b88c807SRodney W. Grimes
934b88c807SRodney W. Grimes
944b88c807SRodney W. Grimes /*
954b88c807SRodney W. Grimes * Called to reset things after an exception.
964b88c807SRodney W. Grimes */
974b88c807SRodney W. Grimes
98338b821bSJilles Tjoelker void
reseteval(void)99338b821bSJilles Tjoelker reseteval(void)
100338b821bSJilles Tjoelker {
1014b88c807SRodney W. Grimes evalskip = 0;
1024b88c807SRodney W. Grimes loopnest = 0;
1034b88c807SRodney W. Grimes }
1044b88c807SRodney W. Grimes
1054b88c807SRodney W. Grimes
1064b88c807SRodney W. Grimes /*
10746be34b9SKris Kennaway * The eval command.
1084b88c807SRodney W. Grimes */
1094b88c807SRodney W. Grimes
110aa9caaf6SPeter Wemm int
evalcmd(int argc,char ** argv)1115134c3f7SWarner Losh evalcmd(int argc, char **argv)
1124b88c807SRodney W. Grimes {
1134b88c807SRodney W. Grimes char *p;
1144b88c807SRodney W. Grimes char *concat;
1154b88c807SRodney W. Grimes char **ap;
1164b88c807SRodney W. Grimes
1174b88c807SRodney W. Grimes if (argc > 1) {
1184b88c807SRodney W. Grimes p = argv[1];
1194b88c807SRodney W. Grimes if (argc > 2) {
1204b88c807SRodney W. Grimes STARTSTACKSTR(concat);
1214b88c807SRodney W. Grimes ap = argv + 2;
1224b88c807SRodney W. Grimes for (;;) {
1239d37e157SJilles Tjoelker STPUTS(p, concat);
1244b88c807SRodney W. Grimes if ((p = *ap++) == NULL)
1254b88c807SRodney W. Grimes break;
1264b88c807SRodney W. Grimes STPUTC(' ', concat);
1274b88c807SRodney W. Grimes }
1284b88c807SRodney W. Grimes STPUTC('\0', concat);
1294b88c807SRodney W. Grimes p = grabstackstr(concat);
1304b88c807SRodney W. Grimes }
131c5aef537SJilles Tjoelker evalstring(p, builtin_flags);
132b84d7af7SJilles Tjoelker } else
133b84d7af7SJilles Tjoelker exitstatus = 0;
1344b88c807SRodney W. Grimes return exitstatus;
1354b88c807SRodney W. Grimes }
1364b88c807SRodney W. Grimes
1374b88c807SRodney W. Grimes
1384b88c807SRodney W. Grimes /*
1394b88c807SRodney W. Grimes * Execute a command or commands contained in a string.
1404b88c807SRodney W. Grimes */
1414b88c807SRodney W. Grimes
1424b88c807SRodney W. Grimes void
evalstring(const char * s,int flags)14322afca9bSJilles Tjoelker evalstring(const char *s, int flags)
1444b88c807SRodney W. Grimes {
1454b88c807SRodney W. Grimes union node *n;
1464b88c807SRodney W. Grimes struct stackmark smark;
147960da934SJilles Tjoelker int flags_exit;
148b84d7af7SJilles Tjoelker int any;
1494b88c807SRodney W. Grimes
150960da934SJilles Tjoelker flags_exit = flags & EV_EXIT;
151960da934SJilles Tjoelker flags &= ~EV_EXIT;
152b84d7af7SJilles Tjoelker any = 0;
1534b88c807SRodney W. Grimes setstackmark(&smark);
1544b88c807SRodney W. Grimes setinputstring(s, 1);
1554b88c807SRodney W. Grimes while ((n = parsecmd(0)) != NEOF) {
1569338c85cSJilles Tjoelker if (n != NULL && !nflag) {
157960da934SJilles Tjoelker if (flags_exit && preadateof())
158960da934SJilles Tjoelker evaltree(n, flags | EV_EXIT);
159960da934SJilles Tjoelker else
160cb806389SStefan Farfeleder evaltree(n, flags);
161b84d7af7SJilles Tjoelker any = 1;
16275e17168SJilles Tjoelker if (evalskip)
16375e17168SJilles Tjoelker break;
164960da934SJilles Tjoelker }
1654b88c807SRodney W. Grimes popstackmark(&smark);
166e9e92235SJilles Tjoelker setstackmark(&smark);
1674b88c807SRodney W. Grimes }
1684b88c807SRodney W. Grimes popfile();
1694b88c807SRodney W. Grimes popstackmark(&smark);
170b84d7af7SJilles Tjoelker if (!any)
171b84d7af7SJilles Tjoelker exitstatus = 0;
172960da934SJilles Tjoelker if (flags_exit)
17345496405SJilles Tjoelker exraise(EXEXIT);
1744b88c807SRodney W. Grimes }
1754b88c807SRodney W. Grimes
1764b88c807SRodney W. Grimes
1774b88c807SRodney W. Grimes /*
1784b88c807SRodney W. Grimes * Evaluate a parse tree. The value is left in the global variable
1794b88c807SRodney W. Grimes * exitstatus.
1804b88c807SRodney W. Grimes */
1814b88c807SRodney W. Grimes
1824b88c807SRodney W. Grimes void
evaltree(union node * n,int flags)1835134c3f7SWarner Losh evaltree(union node *n, int flags)
1844b88c807SRodney W. Grimes {
185457c463dSStefan Farfeleder int do_etest;
186dca867f1SJilles Tjoelker union node *next;
18784edde8bSJilles Tjoelker struct stackmark smark;
188457c463dSStefan Farfeleder
18984edde8bSJilles Tjoelker setstackmark(&smark);
190457c463dSStefan Farfeleder do_etest = 0;
1914b88c807SRodney W. Grimes if (n == NULL) {
1924b88c807SRodney W. Grimes TRACE(("evaltree(NULL) called\n"));
1934b88c807SRodney W. Grimes exitstatus = 0;
1944b88c807SRodney W. Grimes goto out;
1954b88c807SRodney W. Grimes }
196dca867f1SJilles Tjoelker do {
197dca867f1SJilles Tjoelker next = NULL;
198aa9caaf6SPeter Wemm #ifndef NO_HISTORY
1994b88c807SRodney W. Grimes displayhist = 1; /* show history substitutions done with fc */
200aa9caaf6SPeter Wemm #endif
2019957cb23SStefan Farfeleder TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
2024b88c807SRodney W. Grimes switch (n->type) {
2034b88c807SRodney W. Grimes case NSEMI:
2042340828bSStefan Farfeleder evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
2054b88c807SRodney W. Grimes if (evalskip)
2064b88c807SRodney W. Grimes goto out;
207dca867f1SJilles Tjoelker next = n->nbinary.ch2;
2084b88c807SRodney W. Grimes break;
2094b88c807SRodney W. Grimes case NAND:
2104b88c807SRodney W. Grimes evaltree(n->nbinary.ch1, EV_TESTED);
211d1e99272SSteve Price if (evalskip || exitstatus != 0) {
2124b88c807SRodney W. Grimes goto out;
213d1e99272SSteve Price }
214dca867f1SJilles Tjoelker next = n->nbinary.ch2;
2154b88c807SRodney W. Grimes break;
2164b88c807SRodney W. Grimes case NOR:
2174b88c807SRodney W. Grimes evaltree(n->nbinary.ch1, EV_TESTED);
2184b88c807SRodney W. Grimes if (evalskip || exitstatus == 0)
2194b88c807SRodney W. Grimes goto out;
220dca867f1SJilles Tjoelker next = n->nbinary.ch2;
2214b88c807SRodney W. Grimes break;
2224b88c807SRodney W. Grimes case NREDIR:
223c3bb8589SJilles Tjoelker evalredir(n, flags);
2244b88c807SRodney W. Grimes break;
2254b88c807SRodney W. Grimes case NSUBSHELL:
2264b88c807SRodney W. Grimes evalsubshell(n, flags);
227457c463dSStefan Farfeleder do_etest = !(flags & EV_TESTED);
2284b88c807SRodney W. Grimes break;
2294b88c807SRodney W. Grimes case NBACKGND:
2304b88c807SRodney W. Grimes evalsubshell(n, flags);
2314b88c807SRodney W. Grimes break;
2324b88c807SRodney W. Grimes case NIF: {
2334b88c807SRodney W. Grimes evaltree(n->nif.test, EV_TESTED);
2344b88c807SRodney W. Grimes if (evalskip)
2354b88c807SRodney W. Grimes goto out;
236ab0a2172SSteve Price if (exitstatus == 0)
237dca867f1SJilles Tjoelker next = n->nif.ifpart;
238aa9caaf6SPeter Wemm else if (n->nif.elsepart)
239dca867f1SJilles Tjoelker next = n->nif.elsepart;
240ab0a2172SSteve Price else
241ab0a2172SSteve Price exitstatus = 0;
2424b88c807SRodney W. Grimes break;
2434b88c807SRodney W. Grimes }
2444b88c807SRodney W. Grimes case NWHILE:
2454b88c807SRodney W. Grimes case NUNTIL:
2464ee9cb0eSStefan Farfeleder evalloop(n, flags & ~EV_EXIT);
2474b88c807SRodney W. Grimes break;
2484b88c807SRodney W. Grimes case NFOR:
2494ee9cb0eSStefan Farfeleder evalfor(n, flags & ~EV_EXIT);
2504b88c807SRodney W. Grimes break;
2514b88c807SRodney W. Grimes case NCASE:
25293fcb251SJilles Tjoelker next = evalcase(n);
25393fcb251SJilles Tjoelker break;
25493fcb251SJilles Tjoelker case NCLIST:
25593fcb251SJilles Tjoelker next = n->nclist.body;
25693fcb251SJilles Tjoelker break;
25793fcb251SJilles Tjoelker case NCLISTFALLTHRU:
25893fcb251SJilles Tjoelker if (n->nclist.body) {
25993fcb251SJilles Tjoelker evaltree(n->nclist.body, flags & ~EV_EXIT);
26093fcb251SJilles Tjoelker if (evalskip)
26193fcb251SJilles Tjoelker goto out;
26293fcb251SJilles Tjoelker }
26393fcb251SJilles Tjoelker next = n->nclist.next;
2644b88c807SRodney W. Grimes break;
2654b88c807SRodney W. Grimes case NDEFUN:
2664b88c807SRodney W. Grimes defun(n->narg.text, n->narg.next);
2674b88c807SRodney W. Grimes exitstatus = 0;
2684b88c807SRodney W. Grimes break;
2694b88c807SRodney W. Grimes case NNOT:
2704b88c807SRodney W. Grimes evaltree(n->nnot.com, EV_TESTED);
2716e0f89a4SJilles Tjoelker if (evalskip)
2726e0f89a4SJilles Tjoelker goto out;
2734b88c807SRodney W. Grimes exitstatus = !exitstatus;
2744b88c807SRodney W. Grimes break;
2754b88c807SRodney W. Grimes
2764b88c807SRodney W. Grimes case NPIPE:
2774b88c807SRodney W. Grimes evalpipe(n);
278457c463dSStefan Farfeleder do_etest = !(flags & EV_TESTED);
2794b88c807SRodney W. Grimes break;
2804b88c807SRodney W. Grimes case NCMD:
2814b88c807SRodney W. Grimes evalcommand(n, flags, (struct backcmd *)NULL);
282457c463dSStefan Farfeleder do_etest = !(flags & EV_TESTED);
2834b88c807SRodney W. Grimes break;
2844b88c807SRodney W. Grimes default:
2854b88c807SRodney W. Grimes out1fmt("Node type = %d\n", n->type);
2864b88c807SRodney W. Grimes flushout(&output);
2874b88c807SRodney W. Grimes break;
2884b88c807SRodney W. Grimes }
289dca867f1SJilles Tjoelker n = next;
29084edde8bSJilles Tjoelker popstackmark(&smark);
291e9e92235SJilles Tjoelker setstackmark(&smark);
292dca867f1SJilles Tjoelker } while (n != NULL);
2934b88c807SRodney W. Grimes out:
29484edde8bSJilles Tjoelker popstackmark(&smark);
29525e0f0f5SJilles Tjoelker if (pendingsig)
2964b88c807SRodney W. Grimes dotrap();
29745496405SJilles Tjoelker if (eflag && exitstatus != 0 && do_etest)
2984b88c807SRodney W. Grimes exitshell(exitstatus);
29945496405SJilles Tjoelker if (flags & EV_EXIT)
30045496405SJilles Tjoelker exraise(EXEXIT);
3014b88c807SRodney W. Grimes }
3024b88c807SRodney W. Grimes
3034b88c807SRodney W. Grimes
30488328642SDavid E. O'Brien static void
evalloop(union node * n,int flags)3054ee9cb0eSStefan Farfeleder evalloop(union node *n, int flags)
3064b88c807SRodney W. Grimes {
3074b88c807SRodney W. Grimes int status;
3084b88c807SRodney W. Grimes
3094b88c807SRodney W. Grimes loopnest++;
3104b88c807SRodney W. Grimes status = 0;
3114b88c807SRodney W. Grimes for (;;) {
31233c5acf0SJilles Tjoelker if (!evalskip)
3134b88c807SRodney W. Grimes evaltree(n->nbinary.ch1, EV_TESTED);
3144b88c807SRodney W. Grimes if (evalskip) {
31533c5acf0SJilles Tjoelker if (evalskip == SKIPCONT && --skipcount <= 0) {
3164b88c807SRodney W. Grimes evalskip = 0;
3174b88c807SRodney W. Grimes continue;
3184b88c807SRodney W. Grimes }
3194b88c807SRodney W. Grimes if (evalskip == SKIPBREAK && --skipcount <= 0)
3204b88c807SRodney W. Grimes evalskip = 0;
3212935c4ccSJilles Tjoelker if (evalskip == SKIPRETURN)
3228f2dc7deSJilles Tjoelker status = exitstatus;
3234b88c807SRodney W. Grimes break;
3244b88c807SRodney W. Grimes }
3254b88c807SRodney W. Grimes if (n->type == NWHILE) {
3264b88c807SRodney W. Grimes if (exitstatus != 0)
3274b88c807SRodney W. Grimes break;
3284b88c807SRodney W. Grimes } else {
3294b88c807SRodney W. Grimes if (exitstatus == 0)
3304b88c807SRodney W. Grimes break;
3314b88c807SRodney W. Grimes }
3324ee9cb0eSStefan Farfeleder evaltree(n->nbinary.ch2, flags);
3334b88c807SRodney W. Grimes status = exitstatus;
3344b88c807SRodney W. Grimes }
3354b88c807SRodney W. Grimes loopnest--;
3364b88c807SRodney W. Grimes exitstatus = status;
3374b88c807SRodney W. Grimes }
3384b88c807SRodney W. Grimes
3394b88c807SRodney W. Grimes
3404b88c807SRodney W. Grimes
34188328642SDavid E. O'Brien static void
evalfor(union node * n,int flags)3424ee9cb0eSStefan Farfeleder evalfor(union node *n, int flags)
3434b88c807SRodney W. Grimes {
3444b88c807SRodney W. Grimes struct arglist arglist;
3454b88c807SRodney W. Grimes union node *argp;
3468ef0ae8aSJilles Tjoelker int i;
3476eff4a75SJilles Tjoelker int status;
3484b88c807SRodney W. Grimes
3498ef0ae8aSJilles Tjoelker emptyarglist(&arglist);
3504b88c807SRodney W. Grimes for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
351aa9caaf6SPeter Wemm oexitstatus = exitstatus;
3524b88c807SRodney W. Grimes expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3534b88c807SRodney W. Grimes }
3544b88c807SRodney W. Grimes
3554b88c807SRodney W. Grimes loopnest++;
3566eff4a75SJilles Tjoelker status = 0;
3578ef0ae8aSJilles Tjoelker for (i = 0; i < arglist.count; i++) {
3588ef0ae8aSJilles Tjoelker setvar(n->nfor.var, arglist.args[i], 0);
3594ee9cb0eSStefan Farfeleder evaltree(n->nfor.body, flags);
3606eff4a75SJilles Tjoelker status = exitstatus;
3614b88c807SRodney W. Grimes if (evalskip) {
3624b88c807SRodney W. Grimes if (evalskip == SKIPCONT && --skipcount <= 0) {
3634b88c807SRodney W. Grimes evalskip = 0;
3644b88c807SRodney W. Grimes continue;
3654b88c807SRodney W. Grimes }
3664b88c807SRodney W. Grimes if (evalskip == SKIPBREAK && --skipcount <= 0)
3674b88c807SRodney W. Grimes evalskip = 0;
3684b88c807SRodney W. Grimes break;
3694b88c807SRodney W. Grimes }
3704b88c807SRodney W. Grimes }
3714b88c807SRodney W. Grimes loopnest--;
3726eff4a75SJilles Tjoelker exitstatus = status;
3734b88c807SRodney W. Grimes }
3744b88c807SRodney W. Grimes
3754b88c807SRodney W. Grimes
37693fcb251SJilles Tjoelker /*
37793fcb251SJilles Tjoelker * Evaluate a case statement, returning the selected tree.
37893fcb251SJilles Tjoelker *
37993fcb251SJilles Tjoelker * The exit status needs care to get right.
38093fcb251SJilles Tjoelker */
3814b88c807SRodney W. Grimes
382a157dc4dSJilles Tjoelker static union node *
evalcase(union node * n)38393fcb251SJilles Tjoelker evalcase(union node *n)
3844b88c807SRodney W. Grimes {
3854b88c807SRodney W. Grimes union node *cp;
3864b88c807SRodney W. Grimes union node *patp;
3874b88c807SRodney W. Grimes struct arglist arglist;
3884b88c807SRodney W. Grimes
3898ef0ae8aSJilles Tjoelker emptyarglist(&arglist);
390aa9caaf6SPeter Wemm oexitstatus = exitstatus;
3914b88c807SRodney W. Grimes expandarg(n->ncase.expr, &arglist, EXP_TILDE);
392a157dc4dSJilles Tjoelker for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
3934b88c807SRodney W. Grimes for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
3948ef0ae8aSJilles Tjoelker if (casematch(patp, arglist.args[0])) {
395c9afaa63SJilles Tjoelker while (cp->nclist.next &&
39693fcb251SJilles Tjoelker cp->type == NCLISTFALLTHRU &&
39793fcb251SJilles Tjoelker cp->nclist.body == NULL)
398c9afaa63SJilles Tjoelker cp = cp->nclist.next;
39993fcb251SJilles Tjoelker if (cp->nclist.next &&
40093fcb251SJilles Tjoelker cp->type == NCLISTFALLTHRU)
40193fcb251SJilles Tjoelker return (cp);
40292371efcSJilles Tjoelker if (cp->nclist.body == NULL)
40392371efcSJilles Tjoelker exitstatus = 0;
404a157dc4dSJilles Tjoelker return (cp->nclist.body);
4054b88c807SRodney W. Grimes }
4064b88c807SRodney W. Grimes }
4074b88c807SRodney W. Grimes }
40892371efcSJilles Tjoelker exitstatus = 0;
409a157dc4dSJilles Tjoelker return (NULL);
4104b88c807SRodney W. Grimes }
4114b88c807SRodney W. Grimes
4124b88c807SRodney W. Grimes
4134b88c807SRodney W. Grimes
4144b88c807SRodney W. Grimes /*
4154b88c807SRodney W. Grimes * Kick off a subshell to evaluate a tree.
4164b88c807SRodney W. Grimes */
4174b88c807SRodney W. Grimes
41888328642SDavid E. O'Brien static void
evalsubshell(union node * n,int flags)4195134c3f7SWarner Losh evalsubshell(union node *n, int flags)
4204b88c807SRodney W. Grimes {
4214b88c807SRodney W. Grimes struct job *jp;
4224b88c807SRodney W. Grimes int backgnd = (n->type == NBACKGND);
4234b88c807SRodney W. Grimes
424b3f892d9SJilles Tjoelker oexitstatus = exitstatus;
4254b88c807SRodney W. Grimes expredir(n->nredir.redirect);
4264f6e4215SJilles Tjoelker if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
4274f6e4215SJilles Tjoelker forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
4284b88c807SRodney W. Grimes if (backgnd)
4294b88c807SRodney W. Grimes flags &=~ EV_TESTED;
4304b88c807SRodney W. Grimes redirect(n->nredir.redirect, 0);
4314b88c807SRodney W. Grimes evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
432384aedabSJilles Tjoelker } else if (! backgnd) {
4334b88c807SRodney W. Grimes INTOFF;
43457b2932aSMartin Cracauer exitstatus = waitforjob(jp, (int *)NULL);
4354b88c807SRodney W. Grimes INTON;
43603b3a844SJilles Tjoelker } else
43703b3a844SJilles Tjoelker exitstatus = 0;
4384b88c807SRodney W. Grimes }
4394b88c807SRodney W. Grimes
4404b88c807SRodney W. Grimes
441c3bb8589SJilles Tjoelker /*
442c3bb8589SJilles Tjoelker * Evaluate a redirected compound command.
443c3bb8589SJilles Tjoelker */
444c3bb8589SJilles Tjoelker
44588328642SDavid E. O'Brien static void
evalredir(union node * n,int flags)446c3bb8589SJilles Tjoelker evalredir(union node *n, int flags)
447c3bb8589SJilles Tjoelker {
448c3bb8589SJilles Tjoelker struct jmploc jmploc;
449c3bb8589SJilles Tjoelker struct jmploc *savehandler;
450c3bb8589SJilles Tjoelker volatile int in_redirect = 1;
451c3bb8589SJilles Tjoelker
452b3f892d9SJilles Tjoelker oexitstatus = exitstatus;
453c3bb8589SJilles Tjoelker expredir(n->nredir.redirect);
454c3bb8589SJilles Tjoelker savehandler = handler;
455c3bb8589SJilles Tjoelker if (setjmp(jmploc.loc)) {
456c3bb8589SJilles Tjoelker int e;
457c3bb8589SJilles Tjoelker
458c3bb8589SJilles Tjoelker handler = savehandler;
459c3bb8589SJilles Tjoelker e = exception;
460c3bb8589SJilles Tjoelker popredir();
461bb324af6SJilles Tjoelker if (e == EXERROR && in_redirect) {
462eab49982SJilles Tjoelker FORCEINTON;
463c3bb8589SJilles Tjoelker return;
464c3bb8589SJilles Tjoelker }
465c3bb8589SJilles Tjoelker longjmp(handler->loc, 1);
466c3bb8589SJilles Tjoelker } else {
467c3bb8589SJilles Tjoelker INTOFF;
468c3bb8589SJilles Tjoelker handler = &jmploc;
469c3bb8589SJilles Tjoelker redirect(n->nredir.redirect, REDIR_PUSH);
470c3bb8589SJilles Tjoelker in_redirect = 0;
471c3bb8589SJilles Tjoelker INTON;
472c3bb8589SJilles Tjoelker evaltree(n->nredir.n, flags);
473c3bb8589SJilles Tjoelker }
474c3bb8589SJilles Tjoelker INTOFF;
475c3bb8589SJilles Tjoelker handler = savehandler;
476c3bb8589SJilles Tjoelker popredir();
477c3bb8589SJilles Tjoelker INTON;
478c3bb8589SJilles Tjoelker }
479c3bb8589SJilles Tjoelker
4804b88c807SRodney W. Grimes
4814dc6bdd3SJilles Tjoelker static void
exphere(union node * redir,struct arglist * fn)4824dc6bdd3SJilles Tjoelker exphere(union node *redir, struct arglist *fn)
4834dc6bdd3SJilles Tjoelker {
4844dc6bdd3SJilles Tjoelker struct jmploc jmploc;
4854dc6bdd3SJilles Tjoelker struct jmploc *savehandler;
4864dc6bdd3SJilles Tjoelker struct localvar *savelocalvars;
4874dc6bdd3SJilles Tjoelker int need_longjmp = 0;
488adba77a6SJilles Tjoelker unsigned char saveoptreset;
4894dc6bdd3SJilles Tjoelker
490781bfb5aSJilles Tjoelker redir->nhere.expdoc = "";
4914dc6bdd3SJilles Tjoelker savelocalvars = localvars;
4924dc6bdd3SJilles Tjoelker localvars = NULL;
493adba77a6SJilles Tjoelker saveoptreset = shellparam.reset;
4944dc6bdd3SJilles Tjoelker forcelocal++;
4954dc6bdd3SJilles Tjoelker savehandler = handler;
4964dc6bdd3SJilles Tjoelker if (setjmp(jmploc.loc))
497bb324af6SJilles Tjoelker need_longjmp = exception != EXERROR;
4984dc6bdd3SJilles Tjoelker else {
4994dc6bdd3SJilles Tjoelker handler = &jmploc;
5004dc6bdd3SJilles Tjoelker expandarg(redir->nhere.doc, fn, 0);
5018ef0ae8aSJilles Tjoelker redir->nhere.expdoc = fn->args[0];
5024dc6bdd3SJilles Tjoelker INTOFF;
5034dc6bdd3SJilles Tjoelker }
5044dc6bdd3SJilles Tjoelker handler = savehandler;
5054dc6bdd3SJilles Tjoelker forcelocal--;
5064dc6bdd3SJilles Tjoelker poplocalvars();
5074dc6bdd3SJilles Tjoelker localvars = savelocalvars;
508adba77a6SJilles Tjoelker shellparam.reset = saveoptreset;
5094dc6bdd3SJilles Tjoelker if (need_longjmp)
5104dc6bdd3SJilles Tjoelker longjmp(handler->loc, 1);
5114dc6bdd3SJilles Tjoelker INTON;
5124dc6bdd3SJilles Tjoelker }
5134dc6bdd3SJilles Tjoelker
5144dc6bdd3SJilles Tjoelker
5154b88c807SRodney W. Grimes /*
5164b88c807SRodney W. Grimes * Compute the names of the files in a redirection list.
5174b88c807SRodney W. Grimes */
5184b88c807SRodney W. Grimes
51988328642SDavid E. O'Brien static void
expredir(union node * n)5205134c3f7SWarner Losh expredir(union node *n)
5214b88c807SRodney W. Grimes {
522afb033d5SSteve Price union node *redir;
5234b88c807SRodney W. Grimes
5244b88c807SRodney W. Grimes for (redir = n ; redir ; redir = redir->nfile.next) {
5254b88c807SRodney W. Grimes struct arglist fn;
5268ef0ae8aSJilles Tjoelker emptyarglist(&fn);
527aa9caaf6SPeter Wemm switch (redir->type) {
528aa9caaf6SPeter Wemm case NFROM:
529aa9caaf6SPeter Wemm case NTO:
5304682f420SBrian Somers case NFROMTO:
531aa9caaf6SPeter Wemm case NAPPEND:
5321a958c66STim J. Robbins case NCLOBBER:
533f649ab8bSJilles Tjoelker expandarg(redir->nfile.fname, &fn, EXP_TILDE);
5348ef0ae8aSJilles Tjoelker redir->nfile.expfname = fn.args[0];
535aa9caaf6SPeter Wemm break;
536aa9caaf6SPeter Wemm case NFROMFD:
537aa9caaf6SPeter Wemm case NTOFD:
538aa9caaf6SPeter Wemm if (redir->ndup.vname) {
539f649ab8bSJilles Tjoelker expandarg(redir->ndup.vname, &fn, EXP_TILDE);
5408ef0ae8aSJilles Tjoelker fixredir(redir, fn.args[0], 1);
541aa9caaf6SPeter Wemm }
542aa9caaf6SPeter Wemm break;
5434dc6bdd3SJilles Tjoelker case NXHERE:
5444dc6bdd3SJilles Tjoelker exphere(redir, &fn);
5454dc6bdd3SJilles Tjoelker break;
5464b88c807SRodney W. Grimes }
5474b88c807SRodney W. Grimes }
5484b88c807SRodney W. Grimes }
5494b88c807SRodney W. Grimes
5504b88c807SRodney W. Grimes
5514b88c807SRodney W. Grimes
5524b88c807SRodney W. Grimes /*
5534b88c807SRodney W. Grimes * Evaluate a pipeline. All the processes in the pipeline are children
5544b88c807SRodney W. Grimes * of the process creating the pipeline. (This differs from some versions
5554b88c807SRodney W. Grimes * of the shell, which make the last process in a pipeline the parent
5564b88c807SRodney W. Grimes * of all the rest.)
5574b88c807SRodney W. Grimes */
5584b88c807SRodney W. Grimes
55988328642SDavid E. O'Brien static void
evalpipe(union node * n)5605134c3f7SWarner Losh evalpipe(union node *n)
5614b88c807SRodney W. Grimes {
5624b88c807SRodney W. Grimes struct job *jp;
5634b88c807SRodney W. Grimes struct nodelist *lp;
5644b88c807SRodney W. Grimes int pipelen;
5654b88c807SRodney W. Grimes int prevfd;
5664b88c807SRodney W. Grimes int pip[2];
5674b88c807SRodney W. Grimes
5689957cb23SStefan Farfeleder TRACE(("evalpipe(%p) called\n", (void *)n));
5694b88c807SRodney W. Grimes pipelen = 0;
5704b88c807SRodney W. Grimes for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
5714b88c807SRodney W. Grimes pipelen++;
5724b88c807SRodney W. Grimes INTOFF;
5734b88c807SRodney W. Grimes jp = makejob(n, pipelen);
5744b88c807SRodney W. Grimes prevfd = -1;
5754b88c807SRodney W. Grimes for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
5764b88c807SRodney W. Grimes prehash(lp->n);
5774b88c807SRodney W. Grimes pip[1] = -1;
5784b88c807SRodney W. Grimes if (lp->next) {
5794b88c807SRodney W. Grimes if (pipe(pip) < 0) {
58042580a3eSJilles Tjoelker if (prevfd >= 0)
5814b88c807SRodney W. Grimes close(prevfd);
5826c48b6cfSMartin Cracauer error("Pipe call failed: %s", strerror(errno));
5834b88c807SRodney W. Grimes }
5844b88c807SRodney W. Grimes }
5854b88c807SRodney W. Grimes if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
5864b88c807SRodney W. Grimes INTON;
5874b88c807SRodney W. Grimes if (prevfd > 0) {
5887e1c7266SDag-Erling Smørgrav dup2(prevfd, 0);
5894b88c807SRodney W. Grimes close(prevfd);
5904b88c807SRodney W. Grimes }
5914b88c807SRodney W. Grimes if (pip[1] >= 0) {
5926d9efc24SMartin Cracauer if (!(prevfd >= 0 && pip[0] == 0))
5934b88c807SRodney W. Grimes close(pip[0]);
5944b88c807SRodney W. Grimes if (pip[1] != 1) {
5957e1c7266SDag-Erling Smørgrav dup2(pip[1], 1);
5964b88c807SRodney W. Grimes close(pip[1]);
5974b88c807SRodney W. Grimes }
5984b88c807SRodney W. Grimes }
5994b88c807SRodney W. Grimes evaltree(lp->n, EV_EXIT);
6004b88c807SRodney W. Grimes }
6014b88c807SRodney W. Grimes if (prevfd >= 0)
6024b88c807SRodney W. Grimes close(prevfd);
6034b88c807SRodney W. Grimes prevfd = pip[0];
604e64a11e9SJilles Tjoelker if (pip[1] != -1)
6054b88c807SRodney W. Grimes close(pip[1]);
6064b88c807SRodney W. Grimes }
6074b88c807SRodney W. Grimes INTON;
6084b88c807SRodney W. Grimes if (n->npipe.backgnd == 0) {
6094b88c807SRodney W. Grimes INTOFF;
61057b2932aSMartin Cracauer exitstatus = waitforjob(jp, (int *)NULL);
6114b88c807SRodney W. Grimes TRACE(("evalpipe: job done exit status %d\n", exitstatus));
6124b88c807SRodney W. Grimes INTON;
61303b3a844SJilles Tjoelker } else
61403b3a844SJilles Tjoelker exitstatus = 0;
6154b88c807SRodney W. Grimes }
6164b88c807SRodney W. Grimes
6174b88c807SRodney W. Grimes
6184b88c807SRodney W. Grimes
619acd7984fSJilles Tjoelker static int
is_valid_fast_cmdsubst(union node * n)620acd7984fSJilles Tjoelker is_valid_fast_cmdsubst(union node *n)
621acd7984fSJilles Tjoelker {
622acd7984fSJilles Tjoelker
623c543e1aeSJilles Tjoelker return (n->type == NCMD);
624acd7984fSJilles Tjoelker }
625acd7984fSJilles Tjoelker
6264b88c807SRodney W. Grimes /*
6274b88c807SRodney W. Grimes * Execute a command inside back quotes. If it's a builtin command, we
6284b88c807SRodney W. Grimes * want to save its output in a block obtained from malloc. Otherwise
6294b88c807SRodney W. Grimes * we fork off a subprocess and get the output of the command via a pipe.
6304b88c807SRodney W. Grimes * Should be called with interrupts off.
6314b88c807SRodney W. Grimes */
6324b88c807SRodney W. Grimes
6334b88c807SRodney W. Grimes void
evalbackcmd(union node * n,struct backcmd * result)6345134c3f7SWarner Losh evalbackcmd(union node *n, struct backcmd *result)
6354b88c807SRodney W. Grimes {
6364b88c807SRodney W. Grimes int pip[2];
6374b88c807SRodney W. Grimes struct job *jp;
63884edde8bSJilles Tjoelker struct stackmark smark;
63945b71cd1SJilles Tjoelker struct jmploc jmploc;
64045b71cd1SJilles Tjoelker struct jmploc *savehandler;
641c543e1aeSJilles Tjoelker struct localvar *savelocalvars;
642adba77a6SJilles Tjoelker unsigned char saveoptreset;
6434b88c807SRodney W. Grimes
6444b88c807SRodney W. Grimes result->fd = -1;
6454b88c807SRodney W. Grimes result->buf = NULL;
6464b88c807SRodney W. Grimes result->nleft = 0;
6474b88c807SRodney W. Grimes result->jp = NULL;
648aa9caaf6SPeter Wemm if (n == NULL) {
6494b88c807SRodney W. Grimes exitstatus = 0;
65033c5acf0SJilles Tjoelker return;
651aa9caaf6SPeter Wemm }
65233c5acf0SJilles Tjoelker setstackmark(&smark);
653aa9caaf6SPeter Wemm exitstatus = oexitstatus;
654925420d0SJilles Tjoelker if (is_valid_fast_cmdsubst(n)) {
655c543e1aeSJilles Tjoelker savelocalvars = localvars;
656c543e1aeSJilles Tjoelker localvars = NULL;
657adba77a6SJilles Tjoelker saveoptreset = shellparam.reset;
658c543e1aeSJilles Tjoelker forcelocal++;
65945b71cd1SJilles Tjoelker savehandler = handler;
66045b71cd1SJilles Tjoelker if (setjmp(jmploc.loc)) {
661b5532964SJilles Tjoelker if (exception == EXERROR)
662b5532964SJilles Tjoelker /* nothing */;
66345b71cd1SJilles Tjoelker else if (exception != 0) {
66445b71cd1SJilles Tjoelker handler = savehandler;
665c543e1aeSJilles Tjoelker forcelocal--;
666c543e1aeSJilles Tjoelker poplocalvars();
667c543e1aeSJilles Tjoelker localvars = savelocalvars;
668adba77a6SJilles Tjoelker shellparam.reset = saveoptreset;
66945b71cd1SJilles Tjoelker longjmp(handler->loc, 1);
67045b71cd1SJilles Tjoelker }
67145b71cd1SJilles Tjoelker } else {
67245b71cd1SJilles Tjoelker handler = &jmploc;
6734b88c807SRodney W. Grimes evalcommand(n, EV_BACKCMD, result);
67445b71cd1SJilles Tjoelker }
67545b71cd1SJilles Tjoelker handler = savehandler;
676c543e1aeSJilles Tjoelker forcelocal--;
677c543e1aeSJilles Tjoelker poplocalvars();
678c543e1aeSJilles Tjoelker localvars = savelocalvars;
679adba77a6SJilles Tjoelker shellparam.reset = saveoptreset;
6804b88c807SRodney W. Grimes } else {
6814b88c807SRodney W. Grimes if (pipe(pip) < 0)
6826c48b6cfSMartin Cracauer error("Pipe call failed: %s", strerror(errno));
6834b88c807SRodney W. Grimes jp = makejob(n, 1);
6844b88c807SRodney W. Grimes if (forkshell(jp, n, FORK_NOJOB) == 0) {
6854b88c807SRodney W. Grimes FORCEINTON;
6864b88c807SRodney W. Grimes close(pip[0]);
6874b88c807SRodney W. Grimes if (pip[1] != 1) {
6887e1c7266SDag-Erling Smørgrav dup2(pip[1], 1);
6894b88c807SRodney W. Grimes close(pip[1]);
6904b88c807SRodney W. Grimes }
6914b88c807SRodney W. Grimes evaltree(n, EV_EXIT);
6924b88c807SRodney W. Grimes }
6934b88c807SRodney W. Grimes close(pip[1]);
6944b88c807SRodney W. Grimes result->fd = pip[0];
6954b88c807SRodney W. Grimes result->jp = jp;
6964b88c807SRodney W. Grimes }
6974b88c807SRodney W. Grimes popstackmark(&smark);
6986da31df8STim J. Robbins TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
6994b88c807SRodney W. Grimes result->fd, result->buf, result->nleft, result->jp));
7004b88c807SRodney W. Grimes }
7014b88c807SRodney W. Grimes
70284fbdd8cSJilles Tjoelker static int
mustexpandto(const char * argtext,const char * mask)70384fbdd8cSJilles Tjoelker mustexpandto(const char *argtext, const char *mask)
70484fbdd8cSJilles Tjoelker {
70584fbdd8cSJilles Tjoelker for (;;) {
70684fbdd8cSJilles Tjoelker if (*argtext == CTLQUOTEMARK || *argtext == CTLQUOTEEND) {
70784fbdd8cSJilles Tjoelker argtext++;
70884fbdd8cSJilles Tjoelker continue;
70984fbdd8cSJilles Tjoelker }
71084fbdd8cSJilles Tjoelker if (*argtext == CTLESC)
71184fbdd8cSJilles Tjoelker argtext++;
71284fbdd8cSJilles Tjoelker else if (BASESYNTAX[(int)*argtext] == CCTL)
71384fbdd8cSJilles Tjoelker return (0);
71484fbdd8cSJilles Tjoelker if (*argtext != *mask)
71584fbdd8cSJilles Tjoelker return (0);
71684fbdd8cSJilles Tjoelker if (*argtext == '\0')
71784fbdd8cSJilles Tjoelker return (1);
71884fbdd8cSJilles Tjoelker argtext++;
71984fbdd8cSJilles Tjoelker mask++;
72084fbdd8cSJilles Tjoelker }
72184fbdd8cSJilles Tjoelker }
72284fbdd8cSJilles Tjoelker
72384fbdd8cSJilles Tjoelker static int
isdeclarationcmd(struct narg * arg)72484fbdd8cSJilles Tjoelker isdeclarationcmd(struct narg *arg)
72584fbdd8cSJilles Tjoelker {
72684fbdd8cSJilles Tjoelker int have_command = 0;
72784fbdd8cSJilles Tjoelker
72884fbdd8cSJilles Tjoelker if (arg == NULL)
72984fbdd8cSJilles Tjoelker return (0);
73084fbdd8cSJilles Tjoelker while (mustexpandto(arg->text, "command")) {
73184fbdd8cSJilles Tjoelker have_command = 1;
73284fbdd8cSJilles Tjoelker arg = &arg->next->narg;
73384fbdd8cSJilles Tjoelker if (arg == NULL)
73484fbdd8cSJilles Tjoelker return (0);
73584fbdd8cSJilles Tjoelker /*
73684fbdd8cSJilles Tjoelker * To also allow "command -p" and "command --" as part of
73784fbdd8cSJilles Tjoelker * a declaration command, add code here.
73884fbdd8cSJilles Tjoelker * We do not do this, as ksh does not do it either and it
73984fbdd8cSJilles Tjoelker * is not required by POSIX.
74084fbdd8cSJilles Tjoelker */
74184fbdd8cSJilles Tjoelker }
74284fbdd8cSJilles Tjoelker return (mustexpandto(arg->text, "export") ||
74384fbdd8cSJilles Tjoelker mustexpandto(arg->text, "readonly") ||
74484fbdd8cSJilles Tjoelker (mustexpandto(arg->text, "local") &&
74584fbdd8cSJilles Tjoelker (have_command || !isfunc("local"))));
74684fbdd8cSJilles Tjoelker }
74784fbdd8cSJilles Tjoelker
748d1670d42SJilles Tjoelker static void
xtracecommand(struct arglist * varlist,int argc,char ** argv)749046bfe52SJilles Tjoelker xtracecommand(struct arglist *varlist, int argc, char **argv)
750d1670d42SJilles Tjoelker {
751d1670d42SJilles Tjoelker char sep = 0;
7528ef0ae8aSJilles Tjoelker const char *text, *p, *ps4;
7538ef0ae8aSJilles Tjoelker int i;
754d1670d42SJilles Tjoelker
755d1670d42SJilles Tjoelker ps4 = expandstr(ps4val());
756d1670d42SJilles Tjoelker out2str(ps4 != NULL ? ps4 : ps4val());
7578ef0ae8aSJilles Tjoelker for (i = 0; i < varlist->count; i++) {
7588ef0ae8aSJilles Tjoelker text = varlist->args[i];
759d1670d42SJilles Tjoelker if (sep != 0)
760d1670d42SJilles Tjoelker out2c(' ');
7618ef0ae8aSJilles Tjoelker p = strchr(text, '=');
762d1670d42SJilles Tjoelker if (p != NULL) {
763d1670d42SJilles Tjoelker p++;
7648ef0ae8aSJilles Tjoelker outbin(text, p - text, out2);
765d1670d42SJilles Tjoelker out2qstr(p);
766d1670d42SJilles Tjoelker } else
7678ef0ae8aSJilles Tjoelker out2qstr(text);
768d1670d42SJilles Tjoelker sep = ' ';
769d1670d42SJilles Tjoelker }
770046bfe52SJilles Tjoelker for (i = 0; i < argc; i++) {
771046bfe52SJilles Tjoelker text = argv[i];
772d1670d42SJilles Tjoelker if (sep != 0)
773d1670d42SJilles Tjoelker out2c(' ');
7748ef0ae8aSJilles Tjoelker out2qstr(text);
775d1670d42SJilles Tjoelker sep = ' ';
776d1670d42SJilles Tjoelker }
777d1670d42SJilles Tjoelker out2c('\n');
778d1670d42SJilles Tjoelker flushout(&errout);
779d1670d42SJilles Tjoelker }
780d1670d42SJilles Tjoelker
78111535bdfSJilles Tjoelker /*
78211535bdfSJilles Tjoelker * Check if a builtin can safely be executed in the same process,
78311535bdfSJilles Tjoelker * even though it should be in a subshell (command substitution).
78411535bdfSJilles Tjoelker * Note that jobid, jobs, times and trap can show information not
78511535bdfSJilles Tjoelker * available in a child process; this is deliberate.
78611535bdfSJilles Tjoelker * The arguments should already have been expanded.
78711535bdfSJilles Tjoelker */
78811535bdfSJilles Tjoelker static int
safe_builtin(int idx,int argc,char ** argv)78911535bdfSJilles Tjoelker safe_builtin(int idx, int argc, char **argv)
79011535bdfSJilles Tjoelker {
7913ecb77f0SBryan Drewery /* Generated from builtins.def. */
7923ecb77f0SBryan Drewery if (safe_builtin_always(idx))
79311535bdfSJilles Tjoelker return (1);
79411535bdfSJilles Tjoelker if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
79511535bdfSJilles Tjoelker idx == UMASKCMD)
79611535bdfSJilles Tjoelker return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
79711535bdfSJilles Tjoelker if (idx == SETCMD)
79811535bdfSJilles Tjoelker return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
79911535bdfSJilles Tjoelker argv[1][0] == '+') && argv[1][1] == 'o' &&
80011535bdfSJilles Tjoelker argv[1][2] == '\0'));
80111535bdfSJilles Tjoelker return (0);
80211535bdfSJilles Tjoelker }
8034b88c807SRodney W. Grimes
8044b88c807SRodney W. Grimes /*
8054b88c807SRodney W. Grimes * Execute a simple command.
806e23a66acSJilles Tjoelker * Note: This may or may not return if (flags & EV_EXIT).
8074b88c807SRodney W. Grimes */
8084b88c807SRodney W. Grimes
80988328642SDavid E. O'Brien static void
evalcommand(union node * cmd,int flags,struct backcmd * backcmd)8105134c3f7SWarner Losh evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
8114b88c807SRodney W. Grimes {
8124b88c807SRodney W. Grimes union node *argp;
8134b88c807SRodney W. Grimes struct arglist arglist;
8144b88c807SRodney W. Grimes struct arglist varlist;
8154b88c807SRodney W. Grimes char **argv;
8164b88c807SRodney W. Grimes int argc;
8174b88c807SRodney W. Grimes char **envp;
8184b88c807SRodney W. Grimes int varflag;
8194b88c807SRodney W. Grimes int mode;
8204b88c807SRodney W. Grimes int pip[2];
8214b88c807SRodney W. Grimes struct cmdentry cmdentry;
8224b88c807SRodney W. Grimes struct job *jp;
8234b88c807SRodney W. Grimes struct jmploc jmploc;
824224fbf9fSJilles Tjoelker struct jmploc *savehandler;
825224fbf9fSJilles Tjoelker char *savecmdname;
826224fbf9fSJilles Tjoelker struct shparam saveparam;
827224fbf9fSJilles Tjoelker struct localvar *savelocalvars;
828eaa34893SJilles Tjoelker struct parsefile *savetopfile;
8294b88c807SRodney W. Grimes volatile int e;
8304b88c807SRodney W. Grimes char *lastarg;
831c8a5f665SJilles Tjoelker int signaled;
832a436dc79SMartin Cracauer int do_clearcmdentry;
833c5e4fa99SJilles Tjoelker const char *path = pathval();
8348ef0ae8aSJilles Tjoelker int i;
8354b88c807SRodney W. Grimes
8364b88c807SRodney W. Grimes /* First expand the arguments. */
8379957cb23SStefan Farfeleder TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
8388ef0ae8aSJilles Tjoelker emptyarglist(&arglist);
8398ef0ae8aSJilles Tjoelker emptyarglist(&varlist);
8404b88c807SRodney W. Grimes varflag = 1;
841e23a66acSJilles Tjoelker jp = NULL;
842a436dc79SMartin Cracauer do_clearcmdentry = 0;
843aa9caaf6SPeter Wemm oexitstatus = exitstatus;
844aa9caaf6SPeter Wemm exitstatus = 0;
845046bfe52SJilles Tjoelker /* Add one slot at the beginning for tryexec(). */
846046bfe52SJilles Tjoelker appendarglist(&arglist, nullstr);
8474b88c807SRodney W. Grimes for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
84805a447d0SJilles Tjoelker if (varflag && isassignment(argp->narg.text)) {
84984fbdd8cSJilles Tjoelker expandarg(argp, varflag == 1 ? &varlist : &arglist,
85084fbdd8cSJilles Tjoelker EXP_VARTILDE);
8514b88c807SRodney W. Grimes continue;
85284fbdd8cSJilles Tjoelker } else if (varflag == 1)
85384fbdd8cSJilles Tjoelker varflag = isdeclarationcmd(&argp->narg) ? 2 : 0;
8544b88c807SRodney W. Grimes expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8554b88c807SRodney W. Grimes }
856046bfe52SJilles Tjoelker appendarglist(&arglist, nullstr);
8574b88c807SRodney W. Grimes expredir(cmd->ncmd.redirect);
858046bfe52SJilles Tjoelker argc = arglist.count - 2;
859046bfe52SJilles Tjoelker argv = &arglist.args[1];
8604b88c807SRodney W. Grimes
8618ef0ae8aSJilles Tjoelker argv[argc] = NULL;
8624b88c807SRodney W. Grimes lastarg = NULL;
8634b88c807SRodney W. Grimes if (iflag && funcnest == 0 && argc > 0)
8648ef0ae8aSJilles Tjoelker lastarg = argv[argc - 1];
8654b88c807SRodney W. Grimes
8664b88c807SRodney W. Grimes /* Print the command if xflag is set. */
867d1670d42SJilles Tjoelker if (xflag)
868046bfe52SJilles Tjoelker xtracecommand(&varlist, argc, argv);
8694b88c807SRodney W. Grimes
8704b88c807SRodney W. Grimes /* Now locate the command. */
8714b88c807SRodney W. Grimes if (argc == 0) {
87285170a4aSStefan Farfeleder /* Variable assignment(s) without command */
8734b88c807SRodney W. Grimes cmdentry.cmdtype = CMDBUILTIN;
8744b88c807SRodney W. Grimes cmdentry.u.index = BLTINCMD;
8753a64dbc2SJilles Tjoelker cmdentry.special = 0;
8764b88c807SRodney W. Grimes } else {
877aa9caaf6SPeter Wemm static const char PATH[] = "PATH=";
878c848bc18SJilles Tjoelker int cmd_flags = 0, bltinonly = 0;
879aa9caaf6SPeter Wemm
880aa9caaf6SPeter Wemm /*
881aa9caaf6SPeter Wemm * Modify the command lookup path, if a PATH= assignment
882aa9caaf6SPeter Wemm * is present
883aa9caaf6SPeter Wemm */
8848ef0ae8aSJilles Tjoelker for (i = 0; i < varlist.count; i++)
8858ef0ae8aSJilles Tjoelker if (strncmp(varlist.args[i], PATH, sizeof(PATH) - 1) == 0) {
8868ef0ae8aSJilles Tjoelker path = varlist.args[i] + sizeof(PATH) - 1;
887a436dc79SMartin Cracauer /*
888a436dc79SMartin Cracauer * On `PATH=... command`, we need to make
889a436dc79SMartin Cracauer * sure that the command isn't using the
890a436dc79SMartin Cracauer * non-updated hash table of the outer PATH
891a436dc79SMartin Cracauer * setting and we need to make sure that
892a436dc79SMartin Cracauer * the hash table isn't filled with items
893a436dc79SMartin Cracauer * from the temporary setting.
894a436dc79SMartin Cracauer *
89548556dffSElyes HAOUAS * It would be better to forbid using and
896a436dc79SMartin Cracauer * updating the table while this command
897a436dc79SMartin Cracauer * runs, by the command finding mechanism
898a436dc79SMartin Cracauer * is heavily integrated with hash handling,
899a436dc79SMartin Cracauer * so we just delete the hash before and after
900a436dc79SMartin Cracauer * the command runs. Partly deleting like
901a436dc79SMartin Cracauer * changepatch() does doesn't seem worth the
902*c38fe1d2SPei-Ju Chien * booking effort, since most such runs add
9038aa55d81SMaxim Konovalov * directories in front of the new PATH.
904a436dc79SMartin Cracauer */
905c059d822SJilles Tjoelker clearcmdentry();
906a436dc79SMartin Cracauer do_clearcmdentry = 1;
907a436dc79SMartin Cracauer }
908aa9caaf6SPeter Wemm
9094b88c807SRodney W. Grimes for (;;) {
910c848bc18SJilles Tjoelker if (bltinonly) {
911c848bc18SJilles Tjoelker cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
912c848bc18SJilles Tjoelker if (cmdentry.u.index < 0) {
913dc82a6f6SJilles Tjoelker cmdentry.u.index = BLTINCMD;
914dc82a6f6SJilles Tjoelker argv--;
915dc82a6f6SJilles Tjoelker argc++;
916dc82a6f6SJilles Tjoelker break;
9174b88c807SRodney W. Grimes }
918c848bc18SJilles Tjoelker } else
919c848bc18SJilles Tjoelker find_command(argv[0], &cmdentry, cmd_flags, path);
920c848bc18SJilles Tjoelker /* implement the bltin and command builtins here */
921c848bc18SJilles Tjoelker if (cmdentry.cmdtype != CMDBUILTIN)
922c848bc18SJilles Tjoelker break;
923c848bc18SJilles Tjoelker if (cmdentry.u.index == BLTINCMD) {
924c848bc18SJilles Tjoelker if (argc == 1)
925c848bc18SJilles Tjoelker break;
926c848bc18SJilles Tjoelker argv++;
927c848bc18SJilles Tjoelker argc--;
928c848bc18SJilles Tjoelker bltinonly = 1;
929c848bc18SJilles Tjoelker } else if (cmdentry.u.index == COMMANDCMD) {
930c848bc18SJilles Tjoelker if (argc == 1)
931c848bc18SJilles Tjoelker break;
932c848bc18SJilles Tjoelker if (!strcmp(argv[1], "-p")) {
933c848bc18SJilles Tjoelker if (argc == 2)
934c848bc18SJilles Tjoelker break;
935c848bc18SJilles Tjoelker if (argv[2][0] == '-') {
936c848bc18SJilles Tjoelker if (strcmp(argv[2], "--"))
937c848bc18SJilles Tjoelker break;
938c848bc18SJilles Tjoelker if (argc == 3)
939c848bc18SJilles Tjoelker break;
940c848bc18SJilles Tjoelker argv += 3;
941c848bc18SJilles Tjoelker argc -= 3;
942c848bc18SJilles Tjoelker } else {
943c848bc18SJilles Tjoelker argv += 2;
944c848bc18SJilles Tjoelker argc -= 2;
945c848bc18SJilles Tjoelker }
946c848bc18SJilles Tjoelker path = _PATH_STDPATH;
947c059d822SJilles Tjoelker clearcmdentry();
948c848bc18SJilles Tjoelker do_clearcmdentry = 1;
949c848bc18SJilles Tjoelker } else if (!strcmp(argv[1], "--")) {
950c848bc18SJilles Tjoelker if (argc == 2)
951c848bc18SJilles Tjoelker break;
952c848bc18SJilles Tjoelker argv += 2;
953c848bc18SJilles Tjoelker argc -= 2;
954c848bc18SJilles Tjoelker } else if (argv[1][0] == '-')
955c848bc18SJilles Tjoelker break;
956c848bc18SJilles Tjoelker else {
957c848bc18SJilles Tjoelker argv++;
958c848bc18SJilles Tjoelker argc--;
959c848bc18SJilles Tjoelker }
960c848bc18SJilles Tjoelker cmd_flags |= DO_NOFUNC;
961c848bc18SJilles Tjoelker bltinonly = 0;
962c848bc18SJilles Tjoelker } else
9634b88c807SRodney W. Grimes break;
9644b88c807SRodney W. Grimes }
965c848bc18SJilles Tjoelker /*
966c848bc18SJilles Tjoelker * Special builtins lose their special properties when
967c848bc18SJilles Tjoelker * called via 'command'.
968c848bc18SJilles Tjoelker */
969c848bc18SJilles Tjoelker if (cmd_flags & DO_NOFUNC)
970c848bc18SJilles Tjoelker cmdentry.special = 0;
9714b88c807SRodney W. Grimes }
9724b88c807SRodney W. Grimes
9734b88c807SRodney W. Grimes /* Fork off a child process if necessary. */
97447e5204eSJilles Tjoelker if (((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
9756e28dacfSJilles Tjoelker && ((flags & EV_EXIT) == 0 || have_traps()))
976aa9caaf6SPeter Wemm || ((flags & EV_BACKCMD) != 0
97711535bdfSJilles Tjoelker && (cmdentry.cmdtype != CMDBUILTIN ||
97811535bdfSJilles Tjoelker !safe_builtin(cmdentry.u.index, argc, argv)))) {
9794b88c807SRodney W. Grimes jp = makejob(cmd, 1);
98047e5204eSJilles Tjoelker mode = FORK_FG;
9814b88c807SRodney W. Grimes if (flags & EV_BACKCMD) {
9824b88c807SRodney W. Grimes mode = FORK_NOJOB;
9834b88c807SRodney W. Grimes if (pipe(pip) < 0)
9846c48b6cfSMartin Cracauer error("Pipe call failed: %s", strerror(errno));
9854b88c807SRodney W. Grimes }
986caf29fabSJilles Tjoelker if (cmdentry.cmdtype == CMDNORMAL &&
987caf29fabSJilles Tjoelker cmd->ncmd.redirect == NULL &&
9888ef0ae8aSJilles Tjoelker varlist.count == 0 &&
989caf29fabSJilles Tjoelker (mode == FORK_FG || mode == FORK_NOJOB) &&
990caf29fabSJilles Tjoelker !disvforkset() && !iflag && !mflag) {
991caf29fabSJilles Tjoelker vforkexecshell(jp, argv, environment(), path,
992caf29fabSJilles Tjoelker cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
993caf29fabSJilles Tjoelker goto parent;
994caf29fabSJilles Tjoelker }
9954b88c807SRodney W. Grimes if (forkshell(jp, cmd, mode) != 0)
9964b88c807SRodney W. Grimes goto parent; /* at end of routine */
9974b88c807SRodney W. Grimes if (flags & EV_BACKCMD) {
9984b88c807SRodney W. Grimes FORCEINTON;
9994b88c807SRodney W. Grimes close(pip[0]);
10004b88c807SRodney W. Grimes if (pip[1] != 1) {
10017e1c7266SDag-Erling Smørgrav dup2(pip[1], 1);
10024b88c807SRodney W. Grimes close(pip[1]);
10034b88c807SRodney W. Grimes }
1004c5aef537SJilles Tjoelker flags &= ~EV_BACKCMD;
10054b88c807SRodney W. Grimes }
10064b88c807SRodney W. Grimes flags |= EV_EXIT;
10074b88c807SRodney W. Grimes }
10084b88c807SRodney W. Grimes
10094b88c807SRodney W. Grimes /* This is the child process if a fork occurred. */
10104b88c807SRodney W. Grimes /* Execute the command. */
10114b88c807SRodney W. Grimes if (cmdentry.cmdtype == CMDFUNCTION) {
1012ab0a2172SSteve Price #ifdef DEBUG
10134b88c807SRodney W. Grimes trputs("Shell function: "); trargs(argv);
1014ab0a2172SSteve Price #endif
10154b88c807SRodney W. Grimes saveparam = shellparam;
10164b88c807SRodney W. Grimes shellparam.malloc = 0;
1017ab0a2172SSteve Price shellparam.reset = 1;
10184b88c807SRodney W. Grimes shellparam.nparam = argc - 1;
10194b88c807SRodney W. Grimes shellparam.p = argv + 1;
10201bc2fdfaSJilles Tjoelker shellparam.optp = NULL;
10214b88c807SRodney W. Grimes shellparam.optnext = NULL;
10224b88c807SRodney W. Grimes INTOFF;
10234b88c807SRodney W. Grimes savelocalvars = localvars;
10244b88c807SRodney W. Grimes localvars = NULL;
1025eb33e843SJilles Tjoelker reffunc(cmdentry.u.func);
1026224fbf9fSJilles Tjoelker savehandler = handler;
10274b88c807SRodney W. Grimes if (setjmp(jmploc.loc)) {
102817490974SJilles Tjoelker popredir();
1029eb33e843SJilles Tjoelker unreffunc(cmdentry.u.func);
10304b88c807SRodney W. Grimes poplocalvars();
10314b88c807SRodney W. Grimes localvars = savelocalvars;
1032cf45f124SJilles Tjoelker freeparam(&shellparam);
1033cf45f124SJilles Tjoelker shellparam = saveparam;
103492004afeSJilles Tjoelker funcnest--;
10354b88c807SRodney W. Grimes handler = savehandler;
10364b88c807SRodney W. Grimes longjmp(handler->loc, 1);
10374b88c807SRodney W. Grimes }
10384b88c807SRodney W. Grimes handler = &jmploc;
103992004afeSJilles Tjoelker funcnest++;
104017490974SJilles Tjoelker redirect(cmd->ncmd.redirect, REDIR_PUSH);
10419922c6d2SJilles Tjoelker INTON;
10428ef0ae8aSJilles Tjoelker for (i = 0; i < varlist.count; i++)
10438ef0ae8aSJilles Tjoelker mklocal(varlist.args[i]);
104494c53a08SStefan Farfeleder exitstatus = oexitstatus;
104545496405SJilles Tjoelker evaltree(getfuncnode(cmdentry.u.func),
104645496405SJilles Tjoelker flags & (EV_TESTED | EV_EXIT));
10474b88c807SRodney W. Grimes INTOFF;
1048eb33e843SJilles Tjoelker unreffunc(cmdentry.u.func);
10494b88c807SRodney W. Grimes poplocalvars();
10504b88c807SRodney W. Grimes localvars = savelocalvars;
10514b88c807SRodney W. Grimes freeparam(&shellparam);
10524b88c807SRodney W. Grimes shellparam = saveparam;
10534b88c807SRodney W. Grimes handler = savehandler;
105492004afeSJilles Tjoelker funcnest--;
10554b88c807SRodney W. Grimes popredir();
10564b88c807SRodney W. Grimes INTON;
10572935c4ccSJilles Tjoelker if (evalskip == SKIPRETURN) {
10584b88c807SRodney W. Grimes evalskip = 0;
10594b88c807SRodney W. Grimes skipcount = 0;
10604b88c807SRodney W. Grimes }
1061e23a66acSJilles Tjoelker if (jp)
10624b88c807SRodney W. Grimes exitshell(exitstatus);
10634b88c807SRodney W. Grimes } else if (cmdentry.cmdtype == CMDBUILTIN) {
1064ab0a2172SSteve Price #ifdef DEBUG
10654b88c807SRodney W. Grimes trputs("builtin command: "); trargs(argv);
1066ab0a2172SSteve Price #endif
10674b88c807SRodney W. Grimes mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
10684b88c807SRodney W. Grimes if (flags == EV_BACKCMD) {
10694b88c807SRodney W. Grimes memout.nextc = memout.buf;
10704b88c807SRodney W. Grimes mode |= REDIR_BACKQ;
10714b88c807SRodney W. Grimes }
10724b88c807SRodney W. Grimes savecmdname = commandname;
1073eaa34893SJilles Tjoelker savetopfile = getcurrentfile();
10748ef0ae8aSJilles Tjoelker cmdenviron = &varlist;
10754b88c807SRodney W. Grimes e = -1;
1076224fbf9fSJilles Tjoelker savehandler = handler;
10774b88c807SRodney W. Grimes if (setjmp(jmploc.loc)) {
10784b88c807SRodney W. Grimes e = exception;
107945496405SJilles Tjoelker if (e == EXINT)
108045496405SJilles Tjoelker exitstatus = SIGINT+128;
10814b88c807SRodney W. Grimes goto cmddone;
10824b88c807SRodney W. Grimes }
10834b88c807SRodney W. Grimes handler = &jmploc;
108485170a4aSStefan Farfeleder redirect(cmd->ncmd.redirect, mode);
1085d6d66cfcSJilles Tjoelker outclearerror(out1);
10863a64dbc2SJilles Tjoelker /*
10873a64dbc2SJilles Tjoelker * If there is no command word, redirection errors should
10883a64dbc2SJilles Tjoelker * not be fatal but assignment errors should.
10893a64dbc2SJilles Tjoelker */
1090a82f5687SJilles Tjoelker if (argc == 0)
10913a64dbc2SJilles Tjoelker cmdentry.special = 1;
1092850460c0SJilles Tjoelker listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
1093e4b50334SJilles Tjoelker if (argc > 0)
1094e4b50334SJilles Tjoelker bltinsetlocale();
10954b88c807SRodney W. Grimes commandname = argv[0];
10964b88c807SRodney W. Grimes argptr = argv + 1;
1097384aedabSJilles Tjoelker nextopt_optptr = NULL; /* initialize nextopt */
1098cb806389SStefan Farfeleder builtin_flags = flags;
10994b88c807SRodney W. Grimes exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
11004b88c807SRodney W. Grimes flushall();
1101d6d66cfcSJilles Tjoelker if (outiserror(out1)) {
1102d6d66cfcSJilles Tjoelker warning("write error on stdout");
1103d6d66cfcSJilles Tjoelker if (exitstatus == 0 || exitstatus == 1)
1104d6d66cfcSJilles Tjoelker exitstatus = 2;
1105d6d66cfcSJilles Tjoelker }
11064b88c807SRodney W. Grimes cmddone:
1107e4b50334SJilles Tjoelker if (argc > 0)
1108e4b50334SJilles Tjoelker bltinunsetlocale();
1109b2acf887SMartin Cracauer cmdenviron = NULL;
11104b88c807SRodney W. Grimes out1 = &output;
11114b88c807SRodney W. Grimes out2 = &errout;
11124b88c807SRodney W. Grimes freestdout();
1113e23a66acSJilles Tjoelker handler = savehandler;
11144b88c807SRodney W. Grimes commandname = savecmdname;
1115e23a66acSJilles Tjoelker if (jp)
11164b88c807SRodney W. Grimes exitshell(exitstatus);
11174b88c807SRodney W. Grimes if (flags == EV_BACKCMD) {
11184b88c807SRodney W. Grimes backcmd->buf = memout.buf;
11195183ddf2SJilles Tjoelker backcmd->nleft = memout.buf != NULL ?
11205183ddf2SJilles Tjoelker memout.nextc - memout.buf : 0;
11214b88c807SRodney W. Grimes memout.buf = NULL;
11225183ddf2SJilles Tjoelker memout.nextc = NULL;
11235183ddf2SJilles Tjoelker memout.bufend = NULL;
1124de29cd08SJilles Tjoelker memout.bufsize = 64;
11254b88c807SRodney W. Grimes }
112645496405SJilles Tjoelker if (cmdentry.u.index != EXECCMD)
1127544754dfSJilles Tjoelker popredir();
1128f7cc73afSJilles Tjoelker if (e != -1) {
1129bb324af6SJilles Tjoelker if (e != EXERROR || cmdentry.special)
1130f7cc73afSJilles Tjoelker exraise(e);
1131f7cc73afSJilles Tjoelker popfilesupto(savetopfile);
1132f7cc73afSJilles Tjoelker if (flags != EV_BACKCMD)
1133f7cc73afSJilles Tjoelker FORCEINTON;
1134f7cc73afSJilles Tjoelker }
11354b88c807SRodney W. Grimes } else {
1136ab0a2172SSteve Price #ifdef DEBUG
11374b88c807SRodney W. Grimes trputs("normal command: "); trargs(argv);
1138ab0a2172SSteve Price #endif
11394b88c807SRodney W. Grimes redirect(cmd->ncmd.redirect, 0);
11408ef0ae8aSJilles Tjoelker for (i = 0; i < varlist.count; i++)
11418ef0ae8aSJilles Tjoelker setvareq(varlist.args[i], VEXPORT|VSTACK);
11424b88c807SRodney W. Grimes envp = environment();
1143c848bc18SJilles Tjoelker shellexec(argv, envp, path, cmdentry.u.index);
11444b88c807SRodney W. Grimes /*NOTREACHED*/
11454b88c807SRodney W. Grimes }
11464b88c807SRodney W. Grimes goto out;
11474b88c807SRodney W. Grimes
11484b88c807SRodney W. Grimes parent: /* parent process gets here (if we forked) */
114927542743SJilles Tjoelker if (mode == FORK_FG) { /* argument to fork */
11504b88c807SRodney W. Grimes INTOFF;
1151c8a5f665SJilles Tjoelker exitstatus = waitforjob(jp, &signaled);
11524b88c807SRodney W. Grimes INTON;
1153c8a5f665SJilles Tjoelker if (iflag && loopnest > 0 && signaled) {
115444874954SMartin Cracauer evalskip = SKIPBREAK;
115544874954SMartin Cracauer skipcount = loopnest;
115644874954SMartin Cracauer }
115727542743SJilles Tjoelker } else if (mode == FORK_NOJOB) {
11584b88c807SRodney W. Grimes backcmd->fd = pip[0];
11594b88c807SRodney W. Grimes close(pip[1]);
11604b88c807SRodney W. Grimes backcmd->jp = jp;
116147e5204eSJilles Tjoelker }
11624b88c807SRodney W. Grimes
11634b88c807SRodney W. Grimes out:
11644b88c807SRodney W. Grimes if (lastarg)
11654b88c807SRodney W. Grimes setvar("_", lastarg, 0);
1166a436dc79SMartin Cracauer if (do_clearcmdentry)
1167c059d822SJilles Tjoelker clearcmdentry();
11684b88c807SRodney W. Grimes }
11694b88c807SRodney W. Grimes
11704b88c807SRodney W. Grimes
11714b88c807SRodney W. Grimes
11724b88c807SRodney W. Grimes /*
11734b88c807SRodney W. Grimes * Search for a command. This is called before we fork so that the
11744b88c807SRodney W. Grimes * location of the command will be available in the parent as well as
11754b88c807SRodney W. Grimes * the child. The check for "goodname" is an overly conservative
11764b88c807SRodney W. Grimes * check that the name will not be subject to expansion.
11774b88c807SRodney W. Grimes */
11784b88c807SRodney W. Grimes
117988328642SDavid E. O'Brien static void
prehash(union node * n)11805134c3f7SWarner Losh prehash(union node *n)
11814b88c807SRodney W. Grimes {
11824b88c807SRodney W. Grimes struct cmdentry entry;
11834b88c807SRodney W. Grimes
1184cecd2b6cSStefan Farfeleder if (n && n->type == NCMD && n->ncmd.args)
1185aa9caaf6SPeter Wemm if (goodname(n->ncmd.args->narg.text))
1186aa9caaf6SPeter Wemm find_command(n->ncmd.args->narg.text, &entry, 0,
1187aa9caaf6SPeter Wemm pathval());
11884b88c807SRodney W. Grimes }
11894b88c807SRodney W. Grimes
11904b88c807SRodney W. Grimes
11914b88c807SRodney W. Grimes
11924b88c807SRodney W. Grimes /*
11934b88c807SRodney W. Grimes * Builtin commands. Builtin commands whose functions are closely
11944b88c807SRodney W. Grimes * tied to evaluation are implemented here.
11954b88c807SRodney W. Grimes */
11964b88c807SRodney W. Grimes
11974b88c807SRodney W. Grimes /*
1198dc82a6f6SJilles Tjoelker * No command given, a bltin command with no arguments, or a bltin command
1199dc82a6f6SJilles Tjoelker * with an invalid name.
12004b88c807SRodney W. Grimes */
12014b88c807SRodney W. Grimes
1202aa9caaf6SPeter Wemm int
bltincmd(int argc,char ** argv)1203dc82a6f6SJilles Tjoelker bltincmd(int argc, char **argv)
1204aa9caaf6SPeter Wemm {
1205dc82a6f6SJilles Tjoelker if (argc > 1) {
1206dc82a6f6SJilles Tjoelker out2fmt_flush("%s: not found\n", argv[1]);
1207dc82a6f6SJilles Tjoelker return 127;
1208dc82a6f6SJilles Tjoelker }
1209aa9caaf6SPeter Wemm /*
1210b9807277SJilles Tjoelker * Preserve exitstatus of a previous possible command substitution
1211aa9caaf6SPeter Wemm * as POSIX mandates
1212aa9caaf6SPeter Wemm */
12134b88c807SRodney W. Grimes return exitstatus;
12144b88c807SRodney W. Grimes }
12154b88c807SRodney W. Grimes
12164b88c807SRodney W. Grimes
12174b88c807SRodney W. Grimes /*
12184b88c807SRodney W. Grimes * Handle break and continue commands. Break, continue, and return are
12194b88c807SRodney W. Grimes * all handled by setting the evalskip flag. The evaluation routines
12204b88c807SRodney W. Grimes * above all check this flag, and if it is set they start skipping
12214b88c807SRodney W. Grimes * commands rather than executing them. The variable skipcount is
12224b88c807SRodney W. Grimes * the number of loops to break/continue, or the number of function
12234b88c807SRodney W. Grimes * levels to return. (The latter is always 1.) It should probably
12244b88c807SRodney W. Grimes * be an error to break out of more loops than exist, but it isn't
12254b88c807SRodney W. Grimes * in the standard shell so we don't make it one here.
12264b88c807SRodney W. Grimes */
12274b88c807SRodney W. Grimes
1228aa9caaf6SPeter Wemm int
breakcmd(int argc,char ** argv)12295134c3f7SWarner Losh breakcmd(int argc, char **argv)
1230aa9caaf6SPeter Wemm {
12314d34663bSJilles Tjoelker long n;
12324d34663bSJilles Tjoelker char *end;
12334b88c807SRodney W. Grimes
12344d34663bSJilles Tjoelker if (argc > 1) {
12354d34663bSJilles Tjoelker /* Allow arbitrarily large numbers. */
12364d34663bSJilles Tjoelker n = strtol(argv[1], &end, 10);
12374d34663bSJilles Tjoelker if (!is_digit(argv[1][0]) || *end != '\0')
12384d34663bSJilles Tjoelker error("Illegal number: %s", argv[1]);
12394d34663bSJilles Tjoelker } else
12404d34663bSJilles Tjoelker n = 1;
12414b88c807SRodney W. Grimes if (n > loopnest)
12424b88c807SRodney W. Grimes n = loopnest;
12434b88c807SRodney W. Grimes if (n > 0) {
12444b88c807SRodney W. Grimes evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
12454b88c807SRodney W. Grimes skipcount = n;
12464b88c807SRodney W. Grimes }
12474b88c807SRodney W. Grimes return 0;
12484b88c807SRodney W. Grimes }
12494b88c807SRodney W. Grimes
12502babaf74STim J. Robbins /*
12512babaf74STim J. Robbins * The `command' command.
12522babaf74STim J. Robbins */
12532babaf74STim J. Robbins int
commandcmd(int argc __unused,char ** argv __unused)12547cbda738SJilles Tjoelker commandcmd(int argc __unused, char **argv __unused)
12552babaf74STim J. Robbins {
125635ad337dSJilles Tjoelker const char *path;
12572babaf74STim J. Robbins int ch;
1258b2f153feSStefan Farfeleder int cmd = -1;
12592babaf74STim J. Robbins
1260c848bc18SJilles Tjoelker path = bltinlookup("PATH", 1);
12612babaf74STim J. Robbins
12627cbda738SJilles Tjoelker while ((ch = nextopt("pvV")) != '\0') {
12632babaf74STim J. Robbins switch (ch) {
12642babaf74STim J. Robbins case 'p':
126535ad337dSJilles Tjoelker path = _PATH_STDPATH;
12662babaf74STim J. Robbins break;
1267b2f153feSStefan Farfeleder case 'v':
1268b2f153feSStefan Farfeleder cmd = TYPECMD_SMALLV;
1269b2f153feSStefan Farfeleder break;
1270b2f153feSStefan Farfeleder case 'V':
1271b2f153feSStefan Farfeleder cmd = TYPECMD_BIGV;
1272b2f153feSStefan Farfeleder break;
12732babaf74STim J. Robbins }
12742babaf74STim J. Robbins }
12752babaf74STim J. Robbins
1276b2f153feSStefan Farfeleder if (cmd != -1) {
12777cbda738SJilles Tjoelker if (*argptr == NULL || argptr[1] != NULL)
1278b2f153feSStefan Farfeleder error("wrong number of arguments");
12797cbda738SJilles Tjoelker return typecmd_impl(2, argptr - 1, cmd, path);
1280b2f153feSStefan Farfeleder }
12817cbda738SJilles Tjoelker if (*argptr != NULL)
1282274110dfSJilles Tjoelker error("commandcmd bad call");
12832babaf74STim J. Robbins
12842babaf74STim J. Robbins /*
12852babaf74STim J. Robbins * Do nothing successfully if no command was specified;
12862babaf74STim J. Robbins * ksh also does this.
12872babaf74STim J. Robbins */
1288c848bc18SJilles Tjoelker return 0;
12892babaf74STim J. Robbins }
12902babaf74STim J. Robbins
12914b88c807SRodney W. Grimes
12924b88c807SRodney W. Grimes /*
12934b88c807SRodney W. Grimes * The return command.
12944b88c807SRodney W. Grimes */
12954b88c807SRodney W. Grimes
1296aa9caaf6SPeter Wemm int
returncmd(int argc,char ** argv)12975134c3f7SWarner Losh returncmd(int argc, char **argv)
1298aa9caaf6SPeter Wemm {
1299ab0a2172SSteve Price int ret = argc > 1 ? number(argv[1]) : oexitstatus;
13004b88c807SRodney W. Grimes
13012935c4ccSJilles Tjoelker evalskip = SKIPRETURN;
13024b88c807SRodney W. Grimes skipcount = 1;
13034b88c807SRodney W. Grimes return ret;
13044b88c807SRodney W. Grimes }
13054b88c807SRodney W. Grimes
13064b88c807SRodney W. Grimes
1307aa9caaf6SPeter Wemm int
falsecmd(int argc __unused,char ** argv __unused)13085134c3f7SWarner Losh falsecmd(int argc __unused, char **argv __unused)
1309aa9caaf6SPeter Wemm {
1310aa9caaf6SPeter Wemm return 1;
1311aa9caaf6SPeter Wemm }
1312aa9caaf6SPeter Wemm
1313aa9caaf6SPeter Wemm
1314aa9caaf6SPeter Wemm int
truecmd(int argc __unused,char ** argv __unused)13155134c3f7SWarner Losh truecmd(int argc __unused, char **argv __unused)
1316aa9caaf6SPeter Wemm {
13174b88c807SRodney W. Grimes return 0;
13184b88c807SRodney W. Grimes }
13194b88c807SRodney W. Grimes
13204b88c807SRodney W. Grimes
1321aa9caaf6SPeter Wemm int
execcmd(int argc,char ** argv)13225134c3f7SWarner Losh execcmd(int argc, char **argv)
1323aa9caaf6SPeter Wemm {
13248ef0ae8aSJilles Tjoelker int i;
13258ef0ae8aSJilles Tjoelker
1326c1564db0SJilles Tjoelker /*
1327c1564db0SJilles Tjoelker * Because we have historically not supported any options,
1328c1564db0SJilles Tjoelker * only treat "--" specially.
1329c1564db0SJilles Tjoelker */
1330c1564db0SJilles Tjoelker if (argc > 1 && strcmp(argv[1], "--") == 0)
1331c1564db0SJilles Tjoelker argc--, argv++;
13324b88c807SRodney W. Grimes if (argc > 1) {
13334b88c807SRodney W. Grimes iflag = 0; /* exit on error */
13344b88c807SRodney W. Grimes mflag = 0;
13354b88c807SRodney W. Grimes optschanged();
13368ef0ae8aSJilles Tjoelker for (i = 0; i < cmdenviron->count; i++)
13378ef0ae8aSJilles Tjoelker setvareq(cmdenviron->args[i], VEXPORT|VSTACK);
13384b88c807SRodney W. Grimes shellexec(argv + 1, environment(), pathval(), 0);
13394b88c807SRodney W. Grimes
13404b88c807SRodney W. Grimes }
13414b88c807SRodney W. Grimes return 0;
13424b88c807SRodney W. Grimes }
13431974986aSStefan Farfeleder
13441974986aSStefan Farfeleder
13451974986aSStefan Farfeleder int
timescmd(int argc __unused,char ** argv __unused)13461974986aSStefan Farfeleder timescmd(int argc __unused, char **argv __unused)
13471974986aSStefan Farfeleder {
13481974986aSStefan Farfeleder struct rusage ru;
13491974986aSStefan Farfeleder long shumins, shsmins, chumins, chsmins;
13501974986aSStefan Farfeleder double shusecs, shssecs, chusecs, chssecs;
13511974986aSStefan Farfeleder
13521974986aSStefan Farfeleder if (getrusage(RUSAGE_SELF, &ru) < 0)
13531974986aSStefan Farfeleder return 1;
13541974986aSStefan Farfeleder shumins = ru.ru_utime.tv_sec / 60;
13551974986aSStefan Farfeleder shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
13561974986aSStefan Farfeleder shsmins = ru.ru_stime.tv_sec / 60;
13571974986aSStefan Farfeleder shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
13581974986aSStefan Farfeleder if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
13591974986aSStefan Farfeleder return 1;
13601974986aSStefan Farfeleder chumins = ru.ru_utime.tv_sec / 60;
13611974986aSStefan Farfeleder chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
13621974986aSStefan Farfeleder chsmins = ru.ru_stime.tv_sec / 60;
13631974986aSStefan Farfeleder chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
13641974986aSStefan Farfeleder out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
13651974986aSStefan Farfeleder shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
13661974986aSStefan Farfeleder return 0;
13671974986aSStefan Farfeleder }
1368