xref: /original-bsd/bin/sh/eval.c (revision 18fb888a)
1 /*-
2  * Copyright (c) 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 06/08/95";
13 #endif /* not lint */
14 
15 #include <signal.h>
16 #include <unistd.h>
17 
18 /*
19  * Evaluate a command.
20  */
21 
22 #include "shell.h"
23 #include "nodes.h"
24 #include "syntax.h"
25 #include "expand.h"
26 #include "parser.h"
27 #include "jobs.h"
28 #include "eval.h"
29 #include "builtins.h"
30 #include "options.h"
31 #include "exec.h"
32 #include "redir.h"
33 #include "input.h"
34 #include "output.h"
35 #include "trap.h"
36 #include "var.h"
37 #include "memalloc.h"
38 #include "error.h"
39 #include "show.h"
40 #include "mystring.h"
41 #ifndef NO_HISTORY
42 #include "myhistedit.h"
43 #endif
44 
45 
46 /* flags in argument to evaltree */
47 #define EV_EXIT 01		/* exit after evaluating tree */
48 #define EV_TESTED 02		/* exit status is checked; ignore -e flag */
49 #define EV_BACKCMD 04		/* command executing within back quotes */
50 
51 
52 /* reasons for skipping commands (see comment on breakcmd routine) */
53 #define SKIPBREAK 1
54 #define SKIPCONT 2
55 #define SKIPFUNC 3
56 
57 MKINIT int evalskip;		/* set if we are skipping commands */
58 STATIC int skipcount;		/* number of levels to skip */
59 MKINIT int loopnest;		/* current loop nesting level */
60 int funcnest;			/* depth of function calls */
61 
62 
63 char *commandname;
64 struct strlist *cmdenviron;
65 int exitstatus;			/* exit status of last command */
66 int oexitstatus;		/* saved exit status */
67 
68 
69 STATIC void evalloop __P((union node *));
70 STATIC void evalfor __P((union node *));
71 STATIC void evalcase __P((union node *, int));
72 STATIC void evalsubshell __P((union node *, int));
73 STATIC void expredir __P((union node *));
74 STATIC void evalpipe __P((union node *));
75 STATIC void evalcommand __P((union node *, int, struct backcmd *));
76 STATIC void prehash __P((union node *));
77 
78 
79 /*
80  * Called to reset things after an exception.
81  */
82 
83 #ifdef mkinit
84 INCLUDE "eval.h"
85 
86 RESET {
87 	evalskip = 0;
88 	loopnest = 0;
89 	funcnest = 0;
90 }
91 
92 SHELLPROC {
93 	exitstatus = 0;
94 }
95 #endif
96 
97 
98 
99 /*
100  * The eval commmand.
101  */
102 
103 int
evalcmd(argc,argv)104 evalcmd(argc, argv)
105 	int argc;
106 	char **argv;
107 {
108         char *p;
109         char *concat;
110         char **ap;
111 
112         if (argc > 1) {
113                 p = argv[1];
114                 if (argc > 2) {
115                         STARTSTACKSTR(concat);
116                         ap = argv + 2;
117                         for (;;) {
118                                 while (*p)
119                                         STPUTC(*p++, concat);
120                                 if ((p = *ap++) == NULL)
121                                         break;
122                                 STPUTC(' ', concat);
123                         }
124                         STPUTC('\0', concat);
125                         p = grabstackstr(concat);
126                 }
127                 evalstring(p);
128         }
129         return exitstatus;
130 }
131 
132 
133 /*
134  * Execute a command or commands contained in a string.
135  */
136 
137 void
evalstring(s)138 evalstring(s)
139 	char *s;
140 	{
141 	union node *n;
142 	struct stackmark smark;
143 
144 	setstackmark(&smark);
145 	setinputstring(s, 1);
146 	while ((n = parsecmd(0)) != NEOF) {
147 		evaltree(n, 0);
148 		popstackmark(&smark);
149 	}
150 	popfile();
151 	popstackmark(&smark);
152 }
153 
154 
155 
156 /*
157  * Evaluate a parse tree.  The value is left in the global variable
158  * exitstatus.
159  */
160 
161 void
evaltree(n,flags)162 evaltree(n, flags)
163 	union node *n;
164 	int flags;
165 {
166 	if (n == NULL) {
167 		TRACE(("evaltree(NULL) called\n"));
168 		exitstatus = 0;
169 		goto out;
170 	}
171 #ifndef NO_HISTORY
172 	displayhist = 1;	/* show history substitutions done with fc */
173 #endif
174 	TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
175 	switch (n->type) {
176 	case NSEMI:
177 		evaltree(n->nbinary.ch1, 0);
178 		if (evalskip)
179 			goto out;
180 		evaltree(n->nbinary.ch2, flags);
181 		break;
182 	case NAND:
183 		evaltree(n->nbinary.ch1, EV_TESTED);
184 		if (evalskip || exitstatus != 0)
185 			goto out;
186 		evaltree(n->nbinary.ch2, flags);
187 		break;
188 	case NOR:
189 		evaltree(n->nbinary.ch1, EV_TESTED);
190 		if (evalskip || exitstatus == 0)
191 			goto out;
192 		evaltree(n->nbinary.ch2, flags);
193 		break;
194 	case NREDIR:
195 		expredir(n->nredir.redirect);
196 		redirect(n->nredir.redirect, REDIR_PUSH);
197 		evaltree(n->nredir.n, flags);
198 		popredir();
199 		break;
200 	case NSUBSHELL:
201 		evalsubshell(n, flags);
202 		break;
203 	case NBACKGND:
204 		evalsubshell(n, flags);
205 		break;
206 	case NIF: {
207 		int status;
208 
209 		evaltree(n->nif.test, EV_TESTED);
210 		status = exitstatus;
211 		exitstatus = 0;
212 		if (evalskip)
213 			goto out;
214 		if (status == 0)
215 			evaltree(n->nif.ifpart, flags);
216 		else if (n->nif.elsepart)
217 			evaltree(n->nif.elsepart, flags);
218 		break;
219 	}
220 	case NWHILE:
221 	case NUNTIL:
222 		evalloop(n);
223 		break;
224 	case NFOR:
225 		evalfor(n);
226 		break;
227 	case NCASE:
228 		evalcase(n, flags);
229 		break;
230 	case NDEFUN:
231 		defun(n->narg.text, n->narg.next);
232 		exitstatus = 0;
233 		break;
234 	case NNOT:
235 		evaltree(n->nnot.com, EV_TESTED);
236 		exitstatus = !exitstatus;
237 		break;
238 
239 	case NPIPE:
240 		evalpipe(n);
241 		break;
242 	case NCMD:
243 		evalcommand(n, flags, (struct backcmd *)NULL);
244 		break;
245 	default:
246 		out1fmt("Node type = %d\n", n->type);
247 		flushout(&output);
248 		break;
249 	}
250 out:
251 	if (pendingsigs)
252 		dotrap();
253 	if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
254 		exitshell(exitstatus);
255 }
256 
257 
258 STATIC void
evalloop(n)259 evalloop(n)
260 	union node *n;
261 {
262 	int status;
263 
264 	loopnest++;
265 	status = 0;
266 	for (;;) {
267 		evaltree(n->nbinary.ch1, EV_TESTED);
268 		if (evalskip) {
269 skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
270 				evalskip = 0;
271 				continue;
272 			}
273 			if (evalskip == SKIPBREAK && --skipcount <= 0)
274 				evalskip = 0;
275 			break;
276 		}
277 		if (n->type == NWHILE) {
278 			if (exitstatus != 0)
279 				break;
280 		} else {
281 			if (exitstatus == 0)
282 				break;
283 		}
284 		evaltree(n->nbinary.ch2, 0);
285 		status = exitstatus;
286 		if (evalskip)
287 			goto skipping;
288 	}
289 	loopnest--;
290 	exitstatus = status;
291 }
292 
293 
294 
295 STATIC void
evalfor(n)296 evalfor(n)
297     union node *n;
298 {
299 	struct arglist arglist;
300 	union node *argp;
301 	struct strlist *sp;
302 	struct stackmark smark;
303 
304 	setstackmark(&smark);
305 	arglist.lastp = &arglist.list;
306 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
307 		oexitstatus = exitstatus;
308 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
309 		if (evalskip)
310 			goto out;
311 	}
312 	*arglist.lastp = NULL;
313 
314 	exitstatus = 0;
315 	loopnest++;
316 	for (sp = arglist.list ; sp ; sp = sp->next) {
317 		setvar(n->nfor.var, sp->text, 0);
318 		evaltree(n->nfor.body, 0);
319 		if (evalskip) {
320 			if (evalskip == SKIPCONT && --skipcount <= 0) {
321 				evalskip = 0;
322 				continue;
323 			}
324 			if (evalskip == SKIPBREAK && --skipcount <= 0)
325 				evalskip = 0;
326 			break;
327 		}
328 	}
329 	loopnest--;
330 out:
331 	popstackmark(&smark);
332 }
333 
334 
335 
336 STATIC void
evalcase(n,flags)337 evalcase(n, flags)
338 	union node *n;
339 	int flags;
340 {
341 	union node *cp;
342 	union node *patp;
343 	struct arglist arglist;
344 	struct stackmark smark;
345 
346 	setstackmark(&smark);
347 	arglist.lastp = &arglist.list;
348 	oexitstatus = exitstatus;
349 	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
350 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
351 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
352 			if (casematch(patp, arglist.list->text)) {
353 				if (evalskip == 0) {
354 					evaltree(cp->nclist.body, flags);
355 				}
356 				goto out;
357 			}
358 		}
359 	}
360 out:
361 	popstackmark(&smark);
362 }
363 
364 
365 
366 /*
367  * Kick off a subshell to evaluate a tree.
368  */
369 
370 STATIC void
evalsubshell(n,flags)371 evalsubshell(n, flags)
372 	union node *n;
373 	int flags;
374 {
375 	struct job *jp;
376 	int backgnd = (n->type == NBACKGND);
377 
378 	expredir(n->nredir.redirect);
379 	jp = makejob(n, 1);
380 	if (forkshell(jp, n, backgnd) == 0) {
381 		if (backgnd)
382 			flags &=~ EV_TESTED;
383 		redirect(n->nredir.redirect, 0);
384 		evaltree(n->nredir.n, flags | EV_EXIT);	/* never returns */
385 	}
386 	if (! backgnd) {
387 		INTOFF;
388 		exitstatus = waitforjob(jp);
389 		INTON;
390 	}
391 }
392 
393 
394 
395 /*
396  * Compute the names of the files in a redirection list.
397  */
398 
399 STATIC void
expredir(n)400 expredir(n)
401 	union node *n;
402 {
403 	register union node *redir;
404 
405 	for (redir = n ; redir ; redir = redir->nfile.next) {
406 		struct arglist fn;
407 		fn.lastp = &fn.list;
408 		oexitstatus = exitstatus;
409 		switch (redir->type) {
410 		case NFROM:
411 		case NTO:
412 		case NAPPEND:
413 			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
414 			redir->nfile.expfname = fn.list->text;
415 			break;
416 		case NFROMFD:
417 		case NTOFD:
418 			if (redir->ndup.vname) {
419 				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
420 				fixredir(redir, fn.list->text, 1);
421 			}
422 			break;
423 		}
424 	}
425 }
426 
427 
428 
429 /*
430  * Evaluate a pipeline.  All the processes in the pipeline are children
431  * of the process creating the pipeline.  (This differs from some versions
432  * of the shell, which make the last process in a pipeline the parent
433  * of all the rest.)
434  */
435 
436 STATIC void
evalpipe(n)437 evalpipe(n)
438 	union node *n;
439 {
440 	struct job *jp;
441 	struct nodelist *lp;
442 	int pipelen;
443 	int prevfd;
444 	int pip[2];
445 
446 	TRACE(("evalpipe(0x%lx) called\n", (long)n));
447 	pipelen = 0;
448 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
449 		pipelen++;
450 	INTOFF;
451 	jp = makejob(n, pipelen);
452 	prevfd = -1;
453 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
454 		prehash(lp->n);
455 		pip[1] = -1;
456 		if (lp->next) {
457 			if (pipe(pip) < 0) {
458 				close(prevfd);
459 				error("Pipe call failed");
460 			}
461 		}
462 		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
463 			INTON;
464 			if (prevfd > 0) {
465 				close(0);
466 				copyfd(prevfd, 0);
467 				close(prevfd);
468 			}
469 			if (pip[1] >= 0) {
470 				close(pip[0]);
471 				if (pip[1] != 1) {
472 					close(1);
473 					copyfd(pip[1], 1);
474 					close(pip[1]);
475 				}
476 			}
477 			evaltree(lp->n, EV_EXIT);
478 		}
479 		if (prevfd >= 0)
480 			close(prevfd);
481 		prevfd = pip[0];
482 		close(pip[1]);
483 	}
484 	INTON;
485 	if (n->npipe.backgnd == 0) {
486 		INTOFF;
487 		exitstatus = waitforjob(jp);
488 		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
489 		INTON;
490 	}
491 }
492 
493 
494 
495 /*
496  * Execute a command inside back quotes.  If it's a builtin command, we
497  * want to save its output in a block obtained from malloc.  Otherwise
498  * we fork off a subprocess and get the output of the command via a pipe.
499  * Should be called with interrupts off.
500  */
501 
502 void
evalbackcmd(n,result)503 evalbackcmd(n, result)
504 	union node *n;
505 	struct backcmd *result;
506 {
507 	int pip[2];
508 	struct job *jp;
509 	struct stackmark smark;		/* unnecessary */
510 
511 	setstackmark(&smark);
512 	result->fd = -1;
513 	result->buf = NULL;
514 	result->nleft = 0;
515 	result->jp = NULL;
516 	if (n == NULL) {
517 		exitstatus = 0;
518 		goto out;
519 	}
520 	if (n->type == NCMD) {
521 		exitstatus = oexitstatus;
522 		evalcommand(n, EV_BACKCMD, result);
523 	} else {
524 		exitstatus = 0;
525 		if (pipe(pip) < 0)
526 			error("Pipe call failed");
527 		jp = makejob(n, 1);
528 		if (forkshell(jp, n, FORK_NOJOB) == 0) {
529 			FORCEINTON;
530 			close(pip[0]);
531 			if (pip[1] != 1) {
532 				close(1);
533 				copyfd(pip[1], 1);
534 				close(pip[1]);
535 			}
536 			evaltree(n, EV_EXIT);
537 		}
538 		close(pip[1]);
539 		result->fd = pip[0];
540 		result->jp = jp;
541 	}
542 out:
543 	popstackmark(&smark);
544 	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
545 		result->fd, result->buf, result->nleft, result->jp));
546 }
547 
548 
549 
550 /*
551  * Execute a simple command.
552  */
553 
554 STATIC void
evalcommand(cmd,flags,backcmd)555 evalcommand(cmd, flags, backcmd)
556 	union node *cmd;
557 	int flags;
558 	struct backcmd *backcmd;
559 {
560 	struct stackmark smark;
561 	union node *argp;
562 	struct arglist arglist;
563 	struct arglist varlist;
564 	char **argv;
565 	int argc;
566 	char **envp;
567 	int varflag;
568 	struct strlist *sp;
569 	int mode;
570 	int pip[2];
571 	struct cmdentry cmdentry;
572 	struct job *jp;
573 	struct jmploc jmploc;
574 	struct jmploc *volatile savehandler;
575 	char *volatile savecmdname;
576 	volatile struct shparam saveparam;
577 	struct localvar *volatile savelocalvars;
578 	volatile int e;
579 	char *lastarg;
580 #if __GNUC__
581 	/* Avoid longjmp clobbering */
582 	(void) &argv;
583 	(void) &argc;
584 	(void) &lastarg;
585 	(void) &flags;
586 #endif
587 
588 	/* First expand the arguments. */
589 	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
590 	setstackmark(&smark);
591 	arglist.lastp = &arglist.list;
592 	varlist.lastp = &varlist.list;
593 	varflag = 1;
594 	oexitstatus = exitstatus;
595 	exitstatus = 0;
596 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
597 		char *p = argp->narg.text;
598 		if (varflag && is_name(*p)) {
599 			do {
600 				p++;
601 			} while (is_in_name(*p));
602 			if (*p == '=') {
603 				expandarg(argp, &varlist, EXP_VARTILDE);
604 				continue;
605 			}
606 		}
607 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
608 		varflag = 0;
609 	}
610 	*arglist.lastp = NULL;
611 	*varlist.lastp = NULL;
612 	expredir(cmd->ncmd.redirect);
613 	argc = 0;
614 	for (sp = arglist.list ; sp ; sp = sp->next)
615 		argc++;
616 	argv = stalloc(sizeof (char *) * (argc + 1));
617 
618 	for (sp = arglist.list ; sp ; sp = sp->next) {
619 		TRACE(("evalcommand arg: %s\n", sp->text));
620 		*argv++ = sp->text;
621 	}
622 	*argv = NULL;
623 	lastarg = NULL;
624 	if (iflag && funcnest == 0 && argc > 0)
625 		lastarg = argv[-1];
626 	argv -= argc;
627 
628 	/* Print the command if xflag is set. */
629 	if (xflag) {
630 		outc('+', &errout);
631 		for (sp = varlist.list ; sp ; sp = sp->next) {
632 			outc(' ', &errout);
633 			out2str(sp->text);
634 		}
635 		for (sp = arglist.list ; sp ; sp = sp->next) {
636 			outc(' ', &errout);
637 			out2str(sp->text);
638 		}
639 		outc('\n', &errout);
640 		flushout(&errout);
641 	}
642 
643 	/* Now locate the command. */
644 	if (argc == 0) {
645 		cmdentry.cmdtype = CMDBUILTIN;
646 		cmdentry.u.index = BLTINCMD;
647 	} else {
648 		static const char PATH[] = "PATH=";
649 		char *path = pathval();
650 
651 		/*
652 		 * Modify the command lookup path, if a PATH= assignment
653 		 * is present
654 		 */
655 		for (sp = varlist.list ; sp ; sp = sp->next)
656 			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
657 				path = sp->text + sizeof(PATH) - 1;
658 
659 		find_command(argv[0], &cmdentry, 1, path);
660 		if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
661 			exitstatus = 1;
662 			flushout(&errout);
663 			return;
664 		}
665 		/* implement the bltin builtin here */
666 		if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
667 			for (;;) {
668 				argv++;
669 				if (--argc == 0)
670 					break;
671 				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
672 					outfmt(&errout, "%s: not found\n", *argv);
673 					exitstatus = 1;
674 					flushout(&errout);
675 					return;
676 				}
677 				if (cmdentry.u.index != BLTINCMD)
678 					break;
679 			}
680 		}
681 	}
682 
683 	/* Fork off a child process if necessary. */
684 	if (cmd->ncmd.backgnd
685 	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
686 	 || ((flags & EV_BACKCMD) != 0
687 	    && (cmdentry.cmdtype != CMDBUILTIN
688 		 || cmdentry.u.index == DOTCMD
689 		 || cmdentry.u.index == EVALCMD))) {
690 		jp = makejob(cmd, 1);
691 		mode = cmd->ncmd.backgnd;
692 		if (flags & EV_BACKCMD) {
693 			mode = FORK_NOJOB;
694 			if (pipe(pip) < 0)
695 				error("Pipe call failed");
696 		}
697 		if (forkshell(jp, cmd, mode) != 0)
698 			goto parent;	/* at end of routine */
699 		if (flags & EV_BACKCMD) {
700 			FORCEINTON;
701 			close(pip[0]);
702 			if (pip[1] != 1) {
703 				close(1);
704 				copyfd(pip[1], 1);
705 				close(pip[1]);
706 			}
707 		}
708 		flags |= EV_EXIT;
709 	}
710 
711 	/* This is the child process if a fork occurred. */
712 	/* Execute the command. */
713 	if (cmdentry.cmdtype == CMDFUNCTION) {
714 		trputs("Shell function:  ");  trargs(argv);
715 		redirect(cmd->ncmd.redirect, REDIR_PUSH);
716 		saveparam = shellparam;
717 		shellparam.malloc = 0;
718 		shellparam.nparam = argc - 1;
719 		shellparam.p = argv + 1;
720 		shellparam.optnext = NULL;
721 		INTOFF;
722 		savelocalvars = localvars;
723 		localvars = NULL;
724 		INTON;
725 		if (setjmp(jmploc.loc)) {
726 			if (exception == EXSHELLPROC)
727 				freeparam((struct shparam *)&saveparam);
728 			else {
729 				freeparam(&shellparam);
730 				shellparam = saveparam;
731 			}
732 			poplocalvars();
733 			localvars = savelocalvars;
734 			handler = savehandler;
735 			longjmp(handler->loc, 1);
736 		}
737 		savehandler = handler;
738 		handler = &jmploc;
739 		for (sp = varlist.list ; sp ; sp = sp->next)
740 			mklocal(sp->text);
741 		funcnest++;
742 		evaltree(cmdentry.u.func, 0);
743 		funcnest--;
744 		INTOFF;
745 		poplocalvars();
746 		localvars = savelocalvars;
747 		freeparam(&shellparam);
748 		shellparam = saveparam;
749 		handler = savehandler;
750 		popredir();
751 		INTON;
752 		if (evalskip == SKIPFUNC) {
753 			evalskip = 0;
754 			skipcount = 0;
755 		}
756 		if (flags & EV_EXIT)
757 			exitshell(exitstatus);
758 	} else if (cmdentry.cmdtype == CMDBUILTIN) {
759 		trputs("builtin command:  ");  trargs(argv);
760 		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
761 		if (flags == EV_BACKCMD) {
762 			memout.nleft = 0;
763 			memout.nextc = memout.buf;
764 			memout.bufsize = 64;
765 			mode |= REDIR_BACKQ;
766 		}
767 		redirect(cmd->ncmd.redirect, mode);
768 		savecmdname = commandname;
769 		cmdenviron = varlist.list;
770 		e = -1;
771 		if (setjmp(jmploc.loc)) {
772 			e = exception;
773 			exitstatus = (e == EXINT)? SIGINT+128 : 2;
774 			goto cmddone;
775 		}
776 		savehandler = handler;
777 		handler = &jmploc;
778 		commandname = argv[0];
779 		argptr = argv + 1;
780 		optptr = NULL;			/* initialize nextopt */
781 		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
782 		flushall();
783 cmddone:
784 		out1 = &output;
785 		out2 = &errout;
786 		freestdout();
787 		if (e != EXSHELLPROC) {
788 			commandname = savecmdname;
789 			if (flags & EV_EXIT) {
790 				exitshell(exitstatus);
791 			}
792 		}
793 		handler = savehandler;
794 		if (e != -1) {
795 			if (e != EXERROR || cmdentry.u.index == BLTINCMD
796 					       || cmdentry.u.index == DOTCMD
797 					       || cmdentry.u.index == EVALCMD
798 #ifndef NO_HISTORY
799 					       || cmdentry.u.index == HISTCMD
800 #endif
801 					       || cmdentry.u.index == EXECCMD)
802 				exraise(e);
803 			FORCEINTON;
804 		}
805 		if (cmdentry.u.index != EXECCMD)
806 			popredir();
807 		if (flags == EV_BACKCMD) {
808 			backcmd->buf = memout.buf;
809 			backcmd->nleft = memout.nextc - memout.buf;
810 			memout.buf = NULL;
811 		}
812 	} else {
813 		trputs("normal command:  ");  trargs(argv);
814 		clearredir();
815 		redirect(cmd->ncmd.redirect, 0);
816 		for (sp = varlist.list ; sp ; sp = sp->next)
817 			setvareq(sp->text, VEXPORT|VSTACK);
818 		envp = environment();
819 		shellexec(argv, envp, pathval(), cmdentry.u.index);
820 		/*NOTREACHED*/
821 	}
822 	goto out;
823 
824 parent:	/* parent process gets here (if we forked) */
825 	if (mode == 0) {	/* argument to fork */
826 		INTOFF;
827 		exitstatus = waitforjob(jp);
828 		INTON;
829 	} else if (mode == 2) {
830 		backcmd->fd = pip[0];
831 		close(pip[1]);
832 		backcmd->jp = jp;
833 	}
834 
835 out:
836 	if (lastarg)
837 		setvar("_", lastarg, 0);
838 	popstackmark(&smark);
839 }
840 
841 
842 
843 /*
844  * Search for a command.  This is called before we fork so that the
845  * location of the command will be available in the parent as well as
846  * the child.  The check for "goodname" is an overly conservative
847  * check that the name will not be subject to expansion.
848  */
849 
850 STATIC void
prehash(n)851 prehash(n)
852 	union node *n;
853 {
854 	struct cmdentry entry;
855 
856 	if (n->type == NCMD && n->ncmd.args)
857 		if (goodname(n->ncmd.args->narg.text))
858 			find_command(n->ncmd.args->narg.text, &entry, 0,
859 				     pathval());
860 }
861 
862 
863 
864 /*
865  * Builtin commands.  Builtin commands whose functions are closely
866  * tied to evaluation are implemented here.
867  */
868 
869 /*
870  * No command given, or a bltin command with no arguments.  Set the
871  * specified variables.
872  */
873 
874 int
bltincmd(argc,argv)875 bltincmd(argc, argv)
876 	int argc;
877 	char **argv;
878 {
879 	listsetvar(cmdenviron);
880 	/*
881 	 * Preserve exitstatus of a previous possible redirection
882 	 * as POSIX mandates
883 	 */
884 	return exitstatus;
885 }
886 
887 
888 /*
889  * Handle break and continue commands.  Break, continue, and return are
890  * all handled by setting the evalskip flag.  The evaluation routines
891  * above all check this flag, and if it is set they start skipping
892  * commands rather than executing them.  The variable skipcount is
893  * the number of loops to break/continue, or the number of function
894  * levels to return.  (The latter is always 1.)  It should probably
895  * be an error to break out of more loops than exist, but it isn't
896  * in the standard shell so we don't make it one here.
897  */
898 
899 int
breakcmd(argc,argv)900 breakcmd(argc, argv)
901 	int argc;
902 	char **argv;
903 {
904 	int n;
905 
906 	n = 1;
907 	if (argc > 1)
908 		n = number(argv[1]);
909 	if (n > loopnest)
910 		n = loopnest;
911 	if (n > 0) {
912 		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
913 		skipcount = n;
914 	}
915 	return 0;
916 }
917 
918 
919 /*
920  * The return command.
921  */
922 
923 int
returncmd(argc,argv)924 returncmd(argc, argv)
925 	int argc;
926 	char **argv;
927 {
928 	int ret;
929 
930 	ret = exitstatus;
931 	if (argc > 1)
932 		ret = number(argv[1]);
933 	if (funcnest) {
934 		evalskip = SKIPFUNC;
935 		skipcount = 1;
936 	}
937 	return ret;
938 }
939 
940 
941 int
falsecmd(argc,argv)942 falsecmd(argc, argv)
943 	int argc;
944 	char **argv;
945 {
946 	return 1;
947 }
948 
949 
950 int
truecmd(argc,argv)951 truecmd(argc, argv)
952 	int argc;
953 	char **argv;
954 {
955 	return 0;
956 }
957 
958 
959 int
execcmd(argc,argv)960 execcmd(argc, argv)
961 	int argc;
962 	char **argv;
963 {
964 	if (argc > 1) {
965 		struct strlist *sp;
966 
967 		iflag = 0;		/* exit on error */
968 		mflag = 0;
969 		optschanged();
970 		for (sp = cmdenviron; sp ; sp = sp->next)
971 			setvareq(sp->text, VEXPORT|VSTACK);
972 		shellexec(argv + 1, environment(), pathval(), 0);
973 
974 	}
975 	return 0;
976 }
977