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