eval.c revision 45916
1132718Skan/*-
2132718Skan * Copyright (c) 1993
3169689Skan *	The Regents of the University of California.  All rights reserved.
4132718Skan *
5132718Skan * This code is derived from software contributed to Berkeley by
6132718Skan * Kenneth Almquist.
7132718Skan *
8132718Skan * Redistribution and use in source and binary forms, with or without
9132718Skan * modification, are permitted provided that the following conditions
10132718Skan * are met:
11132718Skan * 1. Redistributions of source code must retain the above copyright
12132718Skan *    notice, this list of conditions and the following disclaimer.
13132718Skan * 2. Redistributions in binary form must reproduce the above copyright
14132718Skan *    notice, this list of conditions and the following disclaimer in the
15132718Skan *    documentation and/or other materials provided with the distribution.
16132718Skan * 3. All advertising materials mentioning features or use of this software
17132718Skan *    must display the following acknowledgement:
18132718Skan *	This product includes software developed by the University of
19169689Skan *	California, Berkeley and its contributors.
20169689Skan * 4. Neither the name of the University nor the names of its contributors
21132718Skan *    may be used to endorse or promote products derived from this software
22132718Skan *    without specific prior written permission.
23132718Skan *
24132718Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34132718Skan * SUCH DAMAGE.
35132718Skan */
36146895Skan
37132718Skan#ifndef lint
38146895Skan#if 0
39132718Skanstatic char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 6/8/95";
40132718Skan#endif
41132718Skanstatic const char rcsid[] =
42132718Skan	"$Id: eval.c,v 1.17 1999/04/03 12:55:51 cracauer Exp $";
43132718Skan#endif /* not lint */
44132718Skan
45132718Skan#include <signal.h>
46132718Skan#include <unistd.h>
47132718Skan#include <sys/wait.h> /* For WIFSIGNALED(status) */
48132718Skan
49132718Skan/*
50132718Skan * Evaluate a command.
51132718Skan */
52132718Skan
53146895Skan#include "shell.h"
54146895Skan#include "nodes.h"
55146895Skan#include "syntax.h"
56169689Skan#include "expand.h"
57169689Skan#include "parser.h"
58146895Skan#include "jobs.h"
59146895Skan#include "eval.h"
60146895Skan#include "builtins.h"
61146895Skan#include "options.h"
62146895Skan#include "exec.h"
63132718Skan#include "redir.h"
64132718Skan#include "input.h"
65132718Skan#include "output.h"
66132718Skan#include "trap.h"
67132718Skan#include "var.h"
68132718Skan#include "memalloc.h"
69132718Skan#include "error.h"
70132718Skan#include "show.h"
71132718Skan#include "mystring.h"
72132718Skan#ifndef NO_HISTORY
73132718Skan#include "myhistedit.h"
74132718Skan#endif
75169689Skan
76146895Skan
77132718Skan/* flags in argument to evaltree */
78132718Skan#define EV_EXIT 01		/* exit after evaluating tree */
79132718Skan#define EV_TESTED 02		/* exit status is checked; ignore -e flag */
80132718Skan#define EV_BACKCMD 04		/* command executing within back quotes */
81132718Skan
82132718SkanMKINIT int evalskip;		/* set if we are skipping commands */
83132718SkanSTATIC int skipcount;		/* number of levels to skip */
84132718SkanMKINIT int loopnest;		/* current loop nesting level */
85132718Skanint funcnest;			/* depth of function calls */
86132718Skan
87132718Skan
88132718Skanchar *commandname;
89132718Skanstruct strlist *cmdenviron;
90132718Skanint exitstatus;			/* exit status of last command */
91132718Skanint oexitstatus;		/* saved exit status */
92132718Skan
93132718Skan
94132718SkanSTATIC void evalloop __P((union node *));
95132718SkanSTATIC void evalfor __P((union node *));
96132718SkanSTATIC void evalcase __P((union node *, int));
97132718SkanSTATIC void evalsubshell __P((union node *, int));
98132718SkanSTATIC void expredir __P((union node *));
99132718SkanSTATIC void evalpipe __P((union node *));
100132718SkanSTATIC void evalcommand __P((union node *, int, struct backcmd *));
101132718SkanSTATIC void prehash __P((union node *));
102132718Skan
103132718Skan
104132718Skan/*
105132718Skan * Called to reset things after an exception.
106132718Skan */
107132718Skan
108132718Skan#ifdef mkinit
109132718SkanINCLUDE "eval.h"
110132718Skan
111132718SkanRESET {
112146895Skan	evalskip = 0;
113146895Skan	loopnest = 0;
114146895Skan	funcnest = 0;
115146895Skan}
116146895Skan
117146895SkanSHELLPROC {
118169689Skan	exitstatus = 0;
119146895Skan}
120146895Skan#endif
121146895Skan
122146895Skan
123146895Skan
124146895Skan/*
125146895Skan * The eval commmand.
126146895Skan */
127146895Skan
128146895Skanint
129146895Skanevalcmd(argc, argv)
130146895Skan	int argc;
131146895Skan	char **argv;
132146895Skan{
133146895Skan        char *p;
134146895Skan        char *concat;
135146895Skan        char **ap;
136146895Skan
137146895Skan        if (argc > 1) {
138146895Skan                p = argv[1];
139146895Skan                if (argc > 2) {
140146895Skan                        STARTSTACKSTR(concat);
141146895Skan                        ap = argv + 2;
142146895Skan                        for (;;) {
143146895Skan                                while (*p)
144146895Skan                                        STPUTC(*p++, concat);
145146895Skan                                if ((p = *ap++) == NULL)
146146895Skan                                        break;
147146895Skan                                STPUTC(' ', concat);
148146895Skan                        }
149146895Skan                        STPUTC('\0', concat);
150146895Skan                        p = grabstackstr(concat);
151132718Skan                }
152132718Skan                evalstring(p);
153132718Skan        }
154132718Skan        return exitstatus;
155132718Skan}
156132718Skan
157132718Skan
158169689Skan/*
159132718Skan * Execute a command or commands contained in a string.
160132718Skan */
161132718Skan
162132718Skanvoid
163132718Skanevalstring(s)
164132718Skan	char *s;
165132718Skan	{
166132718Skan	union node *n;
167132718Skan	struct stackmark smark;
168169689Skan
169132718Skan	setstackmark(&smark);
170132718Skan	setinputstring(s, 1);
171132718Skan	while ((n = parsecmd(0)) != NEOF) {
172132718Skan		evaltree(n, 0);
173132718Skan		popstackmark(&smark);
174132718Skan	}
175132718Skan	popfile();
176132718Skan	popstackmark(&smark);
177132718Skan}
178132718Skan
179132718Skan
180132718Skan
181132718Skan/*
182132718Skan * Evaluate a parse tree.  The value is left in the global variable
183132718Skan * exitstatus.
184132718Skan */
185132718Skan
186132718Skanvoid
187132718Skanevaltree(n, flags)
188132718Skan	union node *n;
189132718Skan	int flags;
190132718Skan{
191132718Skan	if (n == NULL) {
192132718Skan		TRACE(("evaltree(NULL) called\n"));
193132718Skan		exitstatus = 0;
194132718Skan		goto out;
195132718Skan	}
196132718Skan#ifndef NO_HISTORY
197132718Skan	displayhist = 1;	/* show history substitutions done with fc */
198132718Skan#endif
199132718Skan	TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
200132718Skan	switch (n->type) {
201132718Skan	case NSEMI:
202132718Skan		evaltree(n->nbinary.ch1, 0);
203132718Skan		if (evalskip)
204132718Skan			goto out;
205132718Skan		evaltree(n->nbinary.ch2, flags);
206132718Skan		break;
207132718Skan	case NAND:
208132718Skan		evaltree(n->nbinary.ch1, EV_TESTED);
209132718Skan		if (evalskip || exitstatus != 0) {
210132718Skan			flags |= EV_TESTED;
211132718Skan			goto out;
212146895Skan		}
213146895Skan		evaltree(n->nbinary.ch2, flags);
214146895Skan		break;
215146895Skan	case NOR:
216146895Skan		evaltree(n->nbinary.ch1, EV_TESTED);
217146895Skan		if (evalskip || exitstatus == 0)
218146895Skan			goto out;
219146895Skan		evaltree(n->nbinary.ch2, flags);
220146895Skan		break;
221146895Skan	case NREDIR:
222146895Skan		expredir(n->nredir.redirect);
223146895Skan		redirect(n->nredir.redirect, REDIR_PUSH);
224146895Skan		evaltree(n->nredir.n, flags);
225146895Skan		popredir();
226146895Skan		break;
227146895Skan	case NSUBSHELL:
228146895Skan		evalsubshell(n, flags);
229146895Skan		break;
230146895Skan	case NBACKGND:
231146895Skan		evalsubshell(n, flags);
232146895Skan		break;
233146895Skan	case NIF: {
234146895Skan		evaltree(n->nif.test, EV_TESTED);
235146895Skan		if (evalskip)
236146895Skan			goto out;
237146895Skan		if (exitstatus == 0)
238146895Skan			evaltree(n->nif.ifpart, flags);
239146895Skan		else if (n->nif.elsepart)
240146895Skan			evaltree(n->nif.elsepart, flags);
241146895Skan		else
242146895Skan			exitstatus = 0;
243146895Skan		break;
244146895Skan	}
245146895Skan	case NWHILE:
246146895Skan	case NUNTIL:
247146895Skan		evalloop(n);
248146895Skan		break;
249146895Skan	case NFOR:
250146895Skan		evalfor(n);
251146895Skan		break;
252146895Skan	case NCASE:
253146895Skan		evalcase(n, flags);
254146895Skan		break;
255146895Skan	case NDEFUN:
256169689Skan		defun(n->narg.text, n->narg.next);
257169689Skan		exitstatus = 0;
258146895Skan		break;
259146895Skan	case NNOT:
260146895Skan		evaltree(n->nnot.com, EV_TESTED);
261146895Skan		exitstatus = !exitstatus;
262146895Skan		break;
263146895Skan
264132718Skan	case NPIPE:
265132718Skan		evalpipe(n);
266132718Skan		break;
267132718Skan	case NCMD:
268132718Skan		evalcommand(n, flags, (struct backcmd *)NULL);
269132718Skan		break;
270132718Skan	default:
271132718Skan		out1fmt("Node type = %d\n", n->type);
272132718Skan		flushout(&output);
273132718Skan		break;
274132718Skan	}
275132718Skanout:
276169689Skan	if (pendingsigs)
277132718Skan		dotrap();
278132718Skan	if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
279132718Skan		exitshell(exitstatus);
280132718Skan}
281169689Skan
282132718Skan
283132718SkanSTATIC void
284132718Skanevalloop(n)
285132718Skan	union node *n;
286132718Skan{
287132718Skan	int status;
288132718Skan
289132718Skan	loopnest++;
290169689Skan	status = 0;
291169689Skan	for (;;) {
292169689Skan		evaltree(n->nbinary.ch1, EV_TESTED);
293169689Skan		if (evalskip) {
294169689Skanskipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
295169689Skan				evalskip = 0;
296169689Skan				continue;
297169689Skan			}
298169689Skan			if (evalskip == SKIPBREAK && --skipcount <= 0)
299169689Skan				evalskip = 0;
300169689Skan			break;
301169689Skan		}
302169689Skan		if (n->type == NWHILE) {
303169689Skan			if (exitstatus != 0)
304169689Skan				break;
305169689Skan		} else {
306169689Skan			if (exitstatus == 0)
307169689Skan				break;
308169689Skan		}
309169689Skan		evaltree(n->nbinary.ch2, 0);
310132718Skan		status = exitstatus;
311132718Skan		if (evalskip)
312132718Skan			goto skipping;
313169689Skan	}
314169689Skan	loopnest--;
315132718Skan	exitstatus = status;
316132718Skan}
317132718Skan
318132718Skan
319132718Skan
320132718SkanSTATIC void
321132718Skanevalfor(n)
322132718Skan    union node *n;
323132718Skan{
324132718Skan	struct arglist arglist;
325132718Skan	union node *argp;
326132718Skan	struct strlist *sp;
327132718Skan	struct stackmark smark;
328132718Skan
329132718Skan	setstackmark(&smark);
330132718Skan	arglist.lastp = &arglist.list;
331169689Skan	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
332132718Skan		oexitstatus = exitstatus;
333169689Skan		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
334132718Skan		if (evalskip)
335132718Skan			goto out;
336132718Skan	}
337132718Skan	*arglist.lastp = NULL;
338169689Skan
339132718Skan	exitstatus = 0;
340169689Skan	loopnest++;
341132718Skan	for (sp = arglist.list ; sp ; sp = sp->next) {
342132718Skan		setvar(n->nfor.var, sp->text, 0);
343132718Skan		evaltree(n->nfor.body, 0);
344132718Skan		if (evalskip) {
345132718Skan			if (evalskip == SKIPCONT && --skipcount <= 0) {
346132718Skan				evalskip = 0;
347132718Skan				continue;
348132718Skan			}
349132718Skan			if (evalskip == SKIPBREAK && --skipcount <= 0)
350169689Skan				evalskip = 0;
351169689Skan			break;
352169689Skan		}
353169689Skan	}
354169689Skan	loopnest--;
355169689Skanout:
356132718Skan	popstackmark(&smark);
357132718Skan}
358132718Skan
359132718Skan
360132718Skan
361132718SkanSTATIC void
362132718Skanevalcase(n, flags)
363132718Skan	union node *n;
364132718Skan	int flags;
365169689Skan{
366169689Skan	union node *cp;
367169689Skan	union node *patp;
368169689Skan	struct arglist arglist;
369169689Skan	struct stackmark smark;
370169689Skan
371132718Skan	setstackmark(&smark);
372132718Skan	arglist.lastp = &arglist.list;
373132718Skan	oexitstatus = exitstatus;
374132718Skan	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
375169689Skan	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
376169689Skan		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
377169689Skan			if (casematch(patp, arglist.list->text)) {
378169689Skan				if (evalskip == 0) {
379169689Skan					evaltree(cp->nclist.body, flags);
380169689Skan				}
381132718Skan				goto out;
382132718Skan			}
383132718Skan		}
384132718Skan	}
385132718Skanout:
386132718Skan	popstackmark(&smark);
387132718Skan}
388132718Skan
389132718Skan
390132718Skan
391132718Skan/*
392132718Skan * Kick off a subshell to evaluate a tree.
393132718Skan */
394132718Skan
395132718SkanSTATIC void
396132718Skanevalsubshell(n, flags)
397132718Skan	union node *n;
398132718Skan	int flags;
399132718Skan{
400132718Skan	struct job *jp;
401132718Skan	int backgnd = (n->type == NBACKGND);
402132718Skan
403132718Skan	expredir(n->nredir.redirect);
404132718Skan	jp = makejob(n, 1);
405132718Skan	if (forkshell(jp, n, backgnd) == 0) {
406132718Skan		if (backgnd)
407132718Skan			flags &=~ EV_TESTED;
408132718Skan		redirect(n->nredir.redirect, 0);
409132718Skan		evaltree(n->nredir.n, flags | EV_EXIT);	/* never returns */
410132718Skan	}
411132718Skan	if (! backgnd) {
412132718Skan		INTOFF;
413132718Skan		exitstatus = waitforjob(jp, (int *)NULL);
414132718Skan		INTON;
415132718Skan	}
416132718Skan}
417132718Skan
418132718Skan
419132718Skan
420132718Skan/*
421132718Skan * Compute the names of the files in a redirection list.
422132718Skan */
423132718Skan
424132718SkanSTATIC void
425132718Skanexpredir(n)
426132718Skan	union node *n;
427132718Skan{
428132718Skan	union node *redir;
429132718Skan
430132718Skan	for (redir = n ; redir ; redir = redir->nfile.next) {
431132718Skan		struct arglist fn;
432132718Skan		fn.lastp = &fn.list;
433132718Skan		oexitstatus = exitstatus;
434132718Skan		switch (redir->type) {
435132718Skan		case NFROM:
436132718Skan		case NTO:
437132718Skan		case NAPPEND:
438132718Skan			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
439132718Skan			redir->nfile.expfname = fn.list->text;
440132718Skan			break;
441132718Skan		case NFROMFD:
442132718Skan		case NTOFD:
443132718Skan			if (redir->ndup.vname) {
444132718Skan				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
445132718Skan				fixredir(redir, fn.list->text, 1);
446132718Skan			}
447132718Skan			break;
448132718Skan		}
449132718Skan	}
450132718Skan}
451132718Skan
452132718Skan
453132718Skan
454132718Skan/*
455169689Skan * Evaluate a pipeline.  All the processes in the pipeline are children
456132718Skan * of the process creating the pipeline.  (This differs from some versions
457132718Skan * of the shell, which make the last process in a pipeline the parent
458132718Skan * of all the rest.)
459169689Skan */
460132718Skan
461132718SkanSTATIC void
462132718Skanevalpipe(n)
463132718Skan	union node *n;
464169689Skan{
465132718Skan	struct job *jp;
466132718Skan	struct nodelist *lp;
467132718Skan	int pipelen;
468132718Skan	int prevfd;
469169689Skan	int pip[2];
470132718Skan
471132718Skan	TRACE(("evalpipe(0x%lx) called\n", (long)n));
472132718Skan	pipelen = 0;
473132718Skan	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
474169689Skan		pipelen++;
475132718Skan	INTOFF;
476132718Skan	jp = makejob(n, pipelen);
477132718Skan	prevfd = -1;
478132718Skan	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
479169689Skan		prehash(lp->n);
480132718Skan		pip[1] = -1;
481132718Skan		if (lp->next) {
482169689Skan			if (pipe(pip) < 0) {
483169689Skan				close(prevfd);
484169689Skan				error("Pipe call failed");
485169689Skan			}
486169689Skan		}
487169689Skan		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
488169689Skan			INTON;
489132718Skan			if (prevfd > 0) {
490132718Skan				close(0);
491132718Skan				copyfd(prevfd, 0);
492132718Skan				close(prevfd);
493132718Skan			}
494132718Skan			if (pip[1] >= 0) {
495132718Skan				close(pip[0]);
496132718Skan				if (pip[1] != 1) {
497132718Skan					close(1);
498132718Skan					copyfd(pip[1], 1);
499132718Skan					close(pip[1]);
500132718Skan				}
501132718Skan			}
502169689Skan			evaltree(lp->n, EV_EXIT);
503169689Skan		}
504169689Skan		if (prevfd >= 0)
505169689Skan			close(prevfd);
506169689Skan		prevfd = pip[0];
507169689Skan		close(pip[1]);
508169689Skan	}
509169689Skan	INTON;
510132718Skan	if (n->npipe.backgnd == 0) {
511132718Skan		INTOFF;
512132718Skan		exitstatus = waitforjob(jp, (int *)NULL);
513132718Skan		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
514169689Skan		INTON;
515169689Skan	}
516169689Skan}
517169689Skan
518169689Skan
519169689Skan
520169689Skan/*
521169689Skan * Execute a command inside back quotes.  If it's a builtin command, we
522169689Skan * want to save its output in a block obtained from malloc.  Otherwise
523169689Skan * we fork off a subprocess and get the output of the command via a pipe.
524169689Skan * Should be called with interrupts off.
525169689Skan */
526169689Skan
527169689Skanvoid
528169689Skanevalbackcmd(n, result)
529169689Skan	union node *n;
530169689Skan	struct backcmd *result;
531169689Skan{
532169689Skan	int pip[2];
533169689Skan	struct job *jp;
534169689Skan	struct stackmark smark;		/* unnecessary */
535169689Skan
536169689Skan	setstackmark(&smark);
537169689Skan	result->fd = -1;
538169689Skan	result->buf = NULL;
539169689Skan	result->nleft = 0;
540169689Skan	result->jp = NULL;
541169689Skan	if (n == NULL) {
542169689Skan		exitstatus = 0;
543169689Skan		goto out;
544169689Skan	}
545169689Skan	if (n->type == NCMD) {
546169689Skan		exitstatus = oexitstatus;
547169689Skan		evalcommand(n, EV_BACKCMD, result);
548169689Skan	} else {
549169689Skan		exitstatus = 0;
550169689Skan		if (pipe(pip) < 0)
551169689Skan			error("Pipe call failed");
552169689Skan		jp = makejob(n, 1);
553169689Skan		if (forkshell(jp, n, FORK_NOJOB) == 0) {
554132718Skan			FORCEINTON;
555132718Skan			close(pip[0]);
556132718Skan			if (pip[1] != 1) {
557132718Skan				close(1);
558132718Skan				copyfd(pip[1], 1);
559132718Skan				close(pip[1]);
560132718Skan			}
561132718Skan			evaltree(n, EV_EXIT);
562132718Skan		}
563132718Skan		close(pip[1]);
564132718Skan		result->fd = pip[0];
565132718Skan		result->jp = jp;
566132718Skan	}
567132718Skanout:
568132718Skan	popstackmark(&smark);
569169689Skan	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
570132718Skan		result->fd, result->buf, result->nleft, result->jp));
571132718Skan}
572132718Skan
573132718Skan
574132718Skan
575132718Skan/*
576132718Skan * Execute a simple command.
577132718Skan */
578132718Skan
579132718SkanSTATIC void
580132718Skanevalcommand(cmd, flags, backcmd)
581132718Skan	union node *cmd;
582132718Skan	int flags;
583132718Skan	struct backcmd *backcmd;
584169689Skan{
585132718Skan	struct stackmark smark;
586132718Skan	union node *argp;
587132718Skan	struct arglist arglist;
588169689Skan	struct arglist varlist;
589132718Skan	char **argv;
590169689Skan	int argc;
591169689Skan	char **envp;
592132718Skan	int varflag;
593169689Skan	struct strlist *sp;
594169689Skan	int mode;
595169689Skan	int pip[2];
596169689Skan	struct cmdentry cmdentry;
597169689Skan	struct job *jp;
598169689Skan	struct jmploc jmploc;
599132718Skan	struct jmploc *volatile savehandler;
600169689Skan	char *volatile savecmdname;
601169689Skan	volatile struct shparam saveparam;
602169689Skan	struct localvar *volatile savelocalvars;
603169689Skan	volatile int e;
604132718Skan	char *lastarg;
605132718Skan	int realstatus;
606132718Skan#if __GNUC__
607132718Skan	/* Avoid longjmp clobbering */
608132718Skan	(void) &argv;
609132718Skan	(void) &argc;
610132718Skan	(void) &lastarg;
611132718Skan	(void) &flags;
612132718Skan#endif
613132718Skan
614132718Skan	/* First expand the arguments. */
615132718Skan	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
616132718Skan	setstackmark(&smark);
617169689Skan	arglist.lastp = &arglist.list;
618132718Skan	varlist.lastp = &varlist.list;
619132718Skan	varflag = 1;
620132718Skan	oexitstatus = exitstatus;
621132718Skan	exitstatus = 0;
622132718Skan	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
623132718Skan		char *p = argp->narg.text;
624132718Skan		if (varflag && is_name(*p)) {
625132718Skan			do {
626132718Skan				p++;
627132718Skan			} while (is_in_name(*p));
628132718Skan			if (*p == '=') {
629132718Skan				expandarg(argp, &varlist, EXP_VARTILDE);
630132718Skan				continue;
631132718Skan			}
632132718Skan		}
633132718Skan		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
634132718Skan		varflag = 0;
635132718Skan	}
636132718Skan	*arglist.lastp = NULL;
637132718Skan	*varlist.lastp = NULL;
638132718Skan	expredir(cmd->ncmd.redirect);
639132718Skan	argc = 0;
640132718Skan	for (sp = arglist.list ; sp ; sp = sp->next)
641132718Skan		argc++;
642132718Skan	argv = stalloc(sizeof (char *) * (argc + 1));
643132718Skan
644132718Skan	for (sp = arglist.list ; sp ; sp = sp->next) {
645132718Skan		TRACE(("evalcommand arg: %s\n", sp->text));
646132718Skan		*argv++ = sp->text;
647132718Skan	}
648132718Skan	*argv = NULL;
649132718Skan	lastarg = NULL;
650132718Skan	if (iflag && funcnest == 0 && argc > 0)
651132718Skan		lastarg = argv[-1];
652132718Skan	argv -= argc;
653132718Skan
654132718Skan	/* Print the command if xflag is set. */
655132718Skan	if (xflag) {
656132718Skan		outc('+', &errout);
657132718Skan		for (sp = varlist.list ; sp ; sp = sp->next) {
658132718Skan			outc(' ', &errout);
659132718Skan			out2str(sp->text);
660132718Skan		}
661132718Skan		for (sp = arglist.list ; sp ; sp = sp->next) {
662132718Skan			outc(' ', &errout);
663132718Skan			out2str(sp->text);
664169689Skan		}
665169689Skan		outc('\n', &errout);
666169689Skan		flushout(&errout);
667169689Skan	}
668132718Skan
669132718Skan	/* Now locate the command. */
670169689Skan	if (argc == 0) {
671169689Skan		cmdentry.cmdtype = CMDBUILTIN;
672132718Skan		cmdentry.u.index = BLTINCMD;
673169689Skan	} else {
674169689Skan		static const char PATH[] = "PATH=";
675132718Skan		char *path = pathval();
676169689Skan
677132718Skan		/*
678169689Skan		 * Modify the command lookup path, if a PATH= assignment
679169689Skan		 * is present
680132718Skan		 */
681132718Skan		for (sp = varlist.list ; sp ; sp = sp->next)
682169689Skan			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
683169689Skan				path = sp->text + sizeof(PATH) - 1;
684169689Skan
685169689Skan		find_command(argv[0], &cmdentry, 1, path);
686132718Skan		if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
687169689Skan			exitstatus = 127;
688169689Skan			flushout(&errout);
689169689Skan			return;
690132718Skan		}
691169689Skan		/* implement the bltin builtin here */
692132718Skan		if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
693132718Skan			for (;;) {
694132718Skan				argv++;
695132718Skan				if (--argc == 0)
696132718Skan					break;
697132718Skan				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
698132718Skan					outfmt(&errout, "%s: not found\n", *argv);
699132718Skan					exitstatus = 127;
700132718Skan					flushout(&errout);
701132718Skan					return;
702132718Skan				}
703132718Skan				if (cmdentry.u.index != BLTINCMD)
704132718Skan					break;
705132718Skan			}
706132718Skan		}
707132718Skan	}
708132718Skan
709132718Skan	/* Fork off a child process if necessary. */
710132718Skan	if (cmd->ncmd.backgnd
711132718Skan	 || (cmdentry.cmdtype == CMDNORMAL
712132718Skan	    && ((flags & EV_EXIT) == 0 || Tflag))
713132718Skan	 || ((flags & EV_BACKCMD) != 0
714132718Skan	    && (cmdentry.cmdtype != CMDBUILTIN
715132718Skan		 || cmdentry.u.index == DOTCMD
716132718Skan		 || cmdentry.u.index == EVALCMD))) {
717132718Skan		jp = makejob(cmd, 1);
718132718Skan		mode = cmd->ncmd.backgnd;
719132718Skan		if (flags & EV_BACKCMD) {
720132718Skan			mode = FORK_NOJOB;
721132718Skan			if (pipe(pip) < 0)
722132718Skan				error("Pipe call failed");
723132718Skan		}
724132718Skan		if (forkshell(jp, cmd, mode) != 0)
725132718Skan			goto parent;	/* at end of routine */
726132718Skan		if (flags & EV_BACKCMD) {
727132718Skan			FORCEINTON;
728132718Skan			close(pip[0]);
729132718Skan			if (pip[1] != 1) {
730132718Skan				close(1);
731169689Skan				copyfd(pip[1], 1);
732169689Skan				close(pip[1]);
733169689Skan			}
734169689Skan		}
735169689Skan		flags |= EV_EXIT;
736169689Skan	}
737169689Skan
738169689Skan	/* This is the child process if a fork occurred. */
739169689Skan	/* Execute the command. */
740169689Skan	if (cmdentry.cmdtype == CMDFUNCTION) {
741169689Skan#ifdef DEBUG
742169689Skan		trputs("Shell function:  ");  trargs(argv);
743169689Skan#endif
744169689Skan		redirect(cmd->ncmd.redirect, REDIR_PUSH);
745169689Skan		saveparam = shellparam;
746169689Skan		shellparam.malloc = 0;
747169689Skan		shellparam.reset = 1;
748169689Skan		shellparam.nparam = argc - 1;
749169689Skan		shellparam.p = argv + 1;
750169689Skan		shellparam.optnext = NULL;
751169689Skan		INTOFF;
752169689Skan		savelocalvars = localvars;
753169689Skan		localvars = NULL;
754169689Skan		INTON;
755169689Skan		if (setjmp(jmploc.loc)) {
756169689Skan			if (exception == EXSHELLPROC)
757169689Skan				freeparam((struct shparam *)&saveparam);
758169689Skan			else {
759169689Skan				freeparam(&shellparam);
760169689Skan				shellparam = saveparam;
761169689Skan			}
762169689Skan			poplocalvars();
763169689Skan			localvars = savelocalvars;
764169689Skan			handler = savehandler;
765169689Skan			longjmp(handler->loc, 1);
766169689Skan		}
767169689Skan		savehandler = handler;
768169689Skan		handler = &jmploc;
769169689Skan		for (sp = varlist.list ; sp ; sp = sp->next)
770169689Skan			mklocal(sp->text);
771169689Skan		funcnest++;
772169689Skan		if (flags & EV_TESTED)
773169689Skan			evaltree(cmdentry.u.func, EV_TESTED);
774169689Skan		else
775169689Skan			evaltree(cmdentry.u.func, 0);
776169689Skan		funcnest--;
777169689Skan		INTOFF;
778169689Skan		poplocalvars();
779169689Skan		localvars = savelocalvars;
780169689Skan		freeparam(&shellparam);
781169689Skan		shellparam = saveparam;
782169689Skan		handler = savehandler;
783132718Skan		popredir();
784132718Skan		INTON;
785169689Skan		if (evalskip == SKIPFUNC) {
786169689Skan			evalskip = 0;
787169689Skan			skipcount = 0;
788169689Skan		}
789132718Skan		if (flags & EV_EXIT)
790132718Skan			exitshell(exitstatus);
791132718Skan	} else if (cmdentry.cmdtype == CMDBUILTIN) {
792132718Skan#ifdef DEBUG
793132718Skan		trputs("builtin command:  ");  trargs(argv);
794132718Skan#endif
795132718Skan		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
796132718Skan		if (flags == EV_BACKCMD) {
797132718Skan			memout.nleft = 0;
798132718Skan			memout.nextc = memout.buf;
799132718Skan			memout.bufsize = 64;
800132718Skan			mode |= REDIR_BACKQ;
801132718Skan		}
802132718Skan		redirect(cmd->ncmd.redirect, mode);
803132718Skan		savecmdname = commandname;
804132718Skan		cmdenviron = varlist.list;
805132718Skan		e = -1;
806132718Skan		if (setjmp(jmploc.loc)) {
807132718Skan			e = exception;
808132718Skan			exitstatus = (e == EXINT)? SIGINT+128 : 2;
809132718Skan			goto cmddone;
810132718Skan		}
811132718Skan		savehandler = handler;
812132718Skan		handler = &jmploc;
813132718Skan		commandname = argv[0];
814132718Skan		argptr = argv + 1;
815169689Skan		optptr = NULL;			/* initialize nextopt */
816169689Skan		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
817169689Skan		flushall();
818169689Skancmddone:
819169689Skan		out1 = &output;
820169689Skan		out2 = &errout;
821132718Skan		freestdout();
822169689Skan		if (e != EXSHELLPROC) {
823169689Skan			commandname = savecmdname;
824169689Skan			if (flags & EV_EXIT) {
825169689Skan				exitshell(exitstatus);
826169689Skan			}
827169689Skan		}
828169689Skan		handler = savehandler;
829169689Skan		if (e != -1) {
830169689Skan			if ((e != EXERROR && e != EXEXEC)
831132718Skan			   || cmdentry.u.index == BLTINCMD
832132718Skan			   || cmdentry.u.index == DOTCMD
833132718Skan			   || cmdentry.u.index == EVALCMD
834132718Skan#ifndef NO_HISTORY
835132718Skan			   || cmdentry.u.index == HISTCMD
836132718Skan#endif
837132718Skan			   || cmdentry.u.index == EXECCMD)
838132718Skan				exraise(e);
839132718Skan			FORCEINTON;
840132718Skan		}
841132718Skan		if (cmdentry.u.index != EXECCMD)
842132718Skan			popredir();
843132718Skan		if (flags == EV_BACKCMD) {
844132718Skan			backcmd->buf = memout.buf;
845132718Skan			backcmd->nleft = memout.nextc - memout.buf;
846132718Skan			memout.buf = NULL;
847132718Skan		}
848132718Skan	} else {
849132718Skan#ifdef DEBUG
850132718Skan		trputs("normal command:  ");  trargs(argv);
851132718Skan#endif
852132718Skan		clearredir();
853132718Skan		redirect(cmd->ncmd.redirect, 0);
854132718Skan		for (sp = varlist.list ; sp ; sp = sp->next)
855132718Skan			setvareq(sp->text, VEXPORT|VSTACK);
856132718Skan		envp = environment();
857132718Skan		shellexec(argv, envp, pathval(), cmdentry.u.index);
858132718Skan		/*NOTREACHED*/
859132718Skan	}
860132718Skan	goto out;
861132718Skan
862132718Skanparent:	/* parent process gets here (if we forked) */
863132718Skan	if (mode == 0) {	/* argument to fork */
864132718Skan		INTOFF;
865132718Skan		exitstatus = waitforjob(jp, &realstatus);
866132718Skan		INTON;
867132718Skan		if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) {
868132718Skan			evalskip = SKIPBREAK;
869132718Skan			skipcount = loopnest;
870132718Skan		}
871132718Skan	} else if (mode == 2) {
872132718Skan		backcmd->fd = pip[0];
873132718Skan		close(pip[1]);
874132718Skan		backcmd->jp = jp;
875132718Skan	}
876132718Skan
877132718Skanout:
878169689Skan	if (lastarg)
879169689Skan		setvar("_", lastarg, 0);
880169689Skan	popstackmark(&smark);
881132718Skan}
882169689Skan
883169689Skan
884169689Skan
885169689Skan/*
886169689Skan * Search for a command.  This is called before we fork so that the
887169689Skan * location of the command will be available in the parent as well as
888169689Skan * the child.  The check for "goodname" is an overly conservative
889169689Skan * check that the name will not be subject to expansion.
890169689Skan */
891169689Skan
892169689SkanSTATIC void
893169689Skanprehash(n)
894169689Skan	union node *n;
895169689Skan{
896132718Skan	struct cmdentry entry;
897132718Skan
898132718Skan	if (n->type == NCMD && n->ncmd.args)
899132718Skan		if (goodname(n->ncmd.args->narg.text))
900132718Skan			find_command(n->ncmd.args->narg.text, &entry, 0,
901132718Skan				     pathval());
902132718Skan}
903132718Skan
904132718Skan
905169689Skan
906169689Skan/*
907169689Skan * Builtin commands.  Builtin commands whose functions are closely
908169689Skan * tied to evaluation are implemented here.
909169689Skan */
910169689Skan
911169689Skan/*
912169689Skan * No command given, or a bltin command with no arguments.  Set the
913169689Skan * specified variables.
914132718Skan */
915169689Skan
916169689Skanint
917169689Skanbltincmd(argc, argv)
918169689Skan	int argc __unused;
919169689Skan	char **argv __unused;
920169689Skan{
921169689Skan	listsetvar(cmdenviron);
922169689Skan	/*
923169689Skan	 * Preserve exitstatus of a previous possible redirection
924169689Skan	 * as POSIX mandates
925169689Skan	 */
926169689Skan	return exitstatus;
927169689Skan}
928169689Skan
929169689Skan
930169689Skan/*
931169689Skan * Handle break and continue commands.  Break, continue, and return are
932169689Skan * all handled by setting the evalskip flag.  The evaluation routines
933169689Skan * above all check this flag, and if it is set they start skipping
934169689Skan * commands rather than executing them.  The variable skipcount is
935169689Skan * the number of loops to break/continue, or the number of function
936169689Skan * levels to return.  (The latter is always 1.)  It should probably
937169689Skan * be an error to break out of more loops than exist, but it isn't
938169689Skan * in the standard shell so we don't make it one here.
939169689Skan */
940169689Skan
941169689Skanint
942169689Skanbreakcmd(argc, argv)
943169689Skan	int argc;
944169689Skan	char **argv;
945169689Skan{
946169689Skan	int n = argc > 1 ? number(argv[1]) : 1;
947169689Skan
948169689Skan	if (n > loopnest)
949169689Skan		n = loopnest;
950169689Skan	if (n > 0) {
951169689Skan		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
952169689Skan		skipcount = n;
953169689Skan	}
954169689Skan	return 0;
955169689Skan}
956169689Skan
957169689Skan
958169689Skan/*
959169689Skan * The return command.
960169689Skan */
961169689Skan
962169689Skanint
963169689Skanreturncmd(argc, argv)
964169689Skan	int argc;
965169689Skan	char **argv;
966169689Skan{
967169689Skan	int ret = argc > 1 ? number(argv[1]) : oexitstatus;
968132718Skan
969132718Skan	if (funcnest) {
970132718Skan		evalskip = SKIPFUNC;
971132718Skan		skipcount = 1;
972132718Skan	} else {
973132718Skan		/* skip the rest of the file */
974132718Skan		evalskip = SKIPFILE;
975132718Skan		skipcount = 1;
976132718Skan	}
977132718Skan	return ret;
978132718Skan}
979132718Skan
980132718Skan
981132718Skanint
982132718Skanfalsecmd(argc, argv)
983132718Skan	int argc __unused;
984132718Skan	char **argv __unused;
985132718Skan{
986132718Skan	return 1;
987132718Skan}
988132718Skan
989132718Skan
990132718Skanint
991132718Skantruecmd(argc, argv)
992132718Skan	int argc __unused;
993132718Skan	char **argv __unused;
994132718Skan{
995132718Skan	return 0;
996169689Skan}
997132718Skan
998132718Skan
999132718Skanint
1000169689Skanexeccmd(argc, argv)
1001132718Skan	int argc;
1002132718Skan	char **argv;
1003132718Skan{
1004132718Skan	if (argc > 1) {
1005132718Skan		struct strlist *sp;
1006132718Skan
1007132718Skan		iflag = 0;		/* exit on error */
1008132718Skan		mflag = 0;
1009132718Skan		optschanged();
1010132718Skan		for (sp = cmdenviron; sp ; sp = sp->next)
1011132718Skan			setvareq(sp->text, VEXPORT|VSTACK);
1012132718Skan		shellexec(argv + 1, environment(), pathval(), 0);
1013132718Skan
1014132718Skan	}
1015132718Skan	return 0;
1016132718Skan}
1017169689Skan