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