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