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