eval.c revision 1.14 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.14 1994/06/14 05:49:19 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 struct arglist fn;
438 fn.lastp = &fn.list;
439 switch (redir->type) {
440 case NFROM:
441 case NTO:
442 case NAPPEND:
443 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
444 redir->nfile.expfname = fn.list->text;
445 break;
446 case NFROMFD:
447 case NTOFD:
448 if (redir->ndup.vname) {
449 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
450 fixredir(redir, fn.list->text, 1);
451 }
452 break;
453 }
454 }
455 }
456
457
458
459 /*
460 * Evaluate a pipeline. All the processes in the pipeline are children
461 * of the process creating the pipeline. (This differs from some versions
462 * of the shell, which make the last process in a pipeline the parent
463 * of all the rest.)
464 */
465
466 STATIC void
467 evalpipe(n)
468 union node *n;
469 {
470 struct job *jp;
471 struct nodelist *lp;
472 int pipelen;
473 int prevfd;
474 int pip[2];
475
476 TRACE(("evalpipe(0x%x) called\n", (int)n));
477 pipelen = 0;
478 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
479 pipelen++;
480 INTOFF;
481 jp = makejob(n, pipelen);
482 prevfd = -1;
483 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
484 prehash(lp->n);
485 pip[1] = -1;
486 if (lp->next) {
487 if (pipe(pip) < 0) {
488 close(prevfd);
489 error("Pipe call failed");
490 }
491 }
492 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
493 INTON;
494 if (prevfd > 0) {
495 close(0);
496 copyfd(prevfd, 0);
497 close(prevfd);
498 }
499 if (pip[1] >= 0) {
500 close(pip[0]);
501 if (pip[1] != 1) {
502 close(1);
503 copyfd(pip[1], 1);
504 close(pip[1]);
505 }
506 }
507 evaltree(lp->n, EV_EXIT);
508 }
509 if (prevfd >= 0)
510 close(prevfd);
511 prevfd = pip[0];
512 close(pip[1]);
513 }
514 INTON;
515 if (n->npipe.backgnd == 0) {
516 INTOFF;
517 exitstatus = waitforjob(jp);
518 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
519 INTON;
520 }
521 }
522
523
524
525 /*
526 * Execute a command inside back quotes. If it's a builtin command, we
527 * want to save its output in a block obtained from malloc. Otherwise
528 * we fork off a subprocess and get the output of the command via a pipe.
529 * Should be called with interrupts off.
530 */
531
532 void
533 evalbackcmd(n, result)
534 union node *n;
535 struct backcmd *result;
536 {
537 int pip[2];
538 struct job *jp;
539 struct stackmark smark; /* unnecessary */
540
541 setstackmark(&smark);
542 result->fd = -1;
543 result->buf = NULL;
544 result->nleft = 0;
545 result->jp = NULL;
546 exitstatus = 0;
547 if (n == NULL)
548 goto out;
549 if (n->type == NCMD) {
550 evalcommand(n, EV_BACKCMD, result);
551 } else {
552 if (pipe(pip) < 0)
553 error("Pipe call failed");
554 jp = makejob(n, 1);
555 if (forkshell(jp, n, FORK_NOJOB) == 0) {
556 FORCEINTON;
557 close(pip[0]);
558 if (pip[1] != 1) {
559 close(1);
560 copyfd(pip[1], 1);
561 close(pip[1]);
562 }
563 evaltree(n, EV_EXIT);
564 }
565 close(pip[1]);
566 result->fd = pip[0];
567 result->jp = jp;
568 }
569 out:
570 popstackmark(&smark);
571 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
572 result->fd, result->buf, result->nleft, result->jp));
573 }
574
575
576
577 /*
578 * Execute a simple command.
579 */
580
581 STATIC void
582 evalcommand(cmd, flags, backcmd)
583 union node *cmd;
584 struct backcmd *backcmd;
585 {
586 struct stackmark smark;
587 union node *argp;
588 struct arglist arglist;
589 struct arglist varlist;
590 char **argv;
591 int argc;
592 char **envp;
593 int varflag;
594 struct strlist *sp;
595 register char *p;
596 int mode;
597 int pip[2];
598 struct cmdentry cmdentry;
599 struct job *jp;
600 struct jmploc jmploc;
601 struct jmploc *volatile savehandler;
602 char *volatile savecmdname;
603 volatile struct shparam saveparam;
604 struct localvar *volatile savelocalvars;
605 volatile int e;
606 char *lastarg;
607
608 /* First expand the arguments. */
609 TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags));
610 setstackmark(&smark);
611 arglist.lastp = &arglist.list;
612 varlist.lastp = &varlist.list;
613 varflag = 1;
614 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
615 p = argp->narg.text;
616 if (varflag && is_name(*p)) {
617 do {
618 p++;
619 } while (is_in_name(*p));
620 if (*p == '=') {
621 expandarg(argp, &varlist, EXP_VARTILDE);
622 continue;
623 }
624 }
625 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
626 varflag = 0;
627 }
628 *arglist.lastp = NULL;
629 *varlist.lastp = NULL;
630 expredir(cmd->ncmd.redirect);
631 argc = 0;
632 for (sp = arglist.list ; sp ; sp = sp->next)
633 argc++;
634 argv = stalloc(sizeof (char *) * (argc + 1));
635
636 for (sp = arglist.list ; sp ; sp = sp->next) {
637 TRACE(("evalcommand arg: %s\n", sp->text));
638 *argv++ = sp->text;
639 }
640 *argv = NULL;
641 lastarg = NULL;
642 if (iflag && funcnest == 0 && argc > 0)
643 lastarg = argv[-1];
644 argv -= argc;
645
646 /* Print the command if xflag is set. */
647 if (xflag) {
648 outc('+', &errout);
649 for (sp = varlist.list ; sp ; sp = sp->next) {
650 outc(' ', &errout);
651 out2str(sp->text);
652 }
653 for (sp = arglist.list ; sp ; sp = sp->next) {
654 outc(' ', &errout);
655 out2str(sp->text);
656 }
657 outc('\n', &errout);
658 flushout(&errout);
659 }
660
661 /* Now locate the command. */
662 if (argc == 0) {
663 cmdentry.cmdtype = CMDBUILTIN;
664 cmdentry.u.index = BLTINCMD;
665 } else {
666 find_command(argv[0], &cmdentry, 1);
667 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
668 exitstatus = 2;
669 flushout(&errout);
670 return;
671 }
672 /* implement the bltin builtin here */
673 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
674 for (;;) {
675 argv++;
676 if (--argc == 0)
677 break;
678 if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
679 outfmt(&errout, "%s: not found\n", *argv);
680 exitstatus = 2;
681 flushout(&errout);
682 return;
683 }
684 if (cmdentry.u.index != BLTINCMD)
685 break;
686 }
687 }
688 }
689
690 /* Fork off a child process if necessary. */
691 if (cmd->ncmd.backgnd
692 || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0
693 || (flags & EV_BACKCMD) != 0
694 && (cmdentry.cmdtype != CMDBUILTIN
695 || cmdentry.u.index == DOTCMD
696 || cmdentry.u.index == EVALCMD)) {
697 jp = makejob(cmd, 1);
698 mode = cmd->ncmd.backgnd;
699 if (flags & EV_BACKCMD) {
700 mode = FORK_NOJOB;
701 if (pipe(pip) < 0)
702 error("Pipe call failed");
703 }
704 if (forkshell(jp, cmd, mode) != 0)
705 goto parent; /* at end of routine */
706 if (flags & EV_BACKCMD) {
707 FORCEINTON;
708 close(pip[0]);
709 if (pip[1] != 1) {
710 close(1);
711 copyfd(pip[1], 1);
712 close(pip[1]);
713 }
714 }
715 flags |= EV_EXIT;
716 }
717
718 /* This is the child process if a fork occurred. */
719 /* Execute the command. */
720 if (cmdentry.cmdtype == CMDFUNCTION) {
721 trputs("Shell function: "); trargs(argv);
722 redirect(cmd->ncmd.redirect, REDIR_PUSH);
723 saveparam = shellparam;
724 shellparam.malloc = 0;
725 shellparam.nparam = argc - 1;
726 shellparam.p = argv + 1;
727 shellparam.optnext = NULL;
728 INTOFF;
729 savelocalvars = localvars;
730 localvars = NULL;
731 INTON;
732 if (setjmp(jmploc.loc)) {
733 if (exception == EXSHELLPROC)
734 freeparam((struct shparam *)&saveparam);
735 else {
736 freeparam(&shellparam);
737 shellparam = saveparam;
738 }
739 poplocalvars();
740 localvars = savelocalvars;
741 handler = savehandler;
742 longjmp(handler->loc, 1);
743 }
744 savehandler = handler;
745 handler = &jmploc;
746 for (sp = varlist.list ; sp ; sp = sp->next)
747 mklocal(sp->text);
748 funcnest++;
749 evaltree(cmdentry.u.func, 0);
750 funcnest--;
751 INTOFF;
752 poplocalvars();
753 localvars = savelocalvars;
754 freeparam(&shellparam);
755 shellparam = saveparam;
756 handler = savehandler;
757 popredir();
758 INTON;
759 if (evalskip == SKIPFUNC) {
760 evalskip = 0;
761 skipcount = 0;
762 }
763 if (flags & EV_EXIT)
764 exitshell(exitstatus);
765 } else if (cmdentry.cmdtype == CMDBUILTIN) {
766 trputs("builtin command: "); trargs(argv);
767 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
768 if (flags == EV_BACKCMD) {
769 memout.nleft = 0;
770 memout.nextc = memout.buf;
771 memout.bufsize = 64;
772 mode |= REDIR_BACKQ;
773 }
774 redirect(cmd->ncmd.redirect, mode);
775 savecmdname = commandname;
776 cmdenviron = varlist.list;
777 e = -1;
778 if (setjmp(jmploc.loc)) {
779 e = exception;
780 exitstatus = (e == EXINT)? SIGINT+128 : 2;
781 goto cmddone;
782 }
783 savehandler = handler;
784 handler = &jmploc;
785 commandname = argv[0];
786 argptr = argv + 1;
787 optptr = NULL; /* initialize nextopt */
788 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
789 flushall();
790 cmddone:
791 out1 = &output;
792 out2 = &errout;
793 freestdout();
794 if (e != EXSHELLPROC) {
795 commandname = savecmdname;
796 if (flags & EV_EXIT) {
797 exitshell(exitstatus);
798 }
799 }
800 handler = savehandler;
801 if (e != -1) {
802 if (e != EXERROR || cmdentry.u.index == BLTINCMD
803 || cmdentry.u.index == DOTCMD
804 || cmdentry.u.index == EVALCMD
805 #ifndef NO_HISTORY
806 || cmdentry.u.index == HISTCMD
807 #endif
808 || cmdentry.u.index == EXECCMD)
809 exraise(e);
810 FORCEINTON;
811 }
812 if (cmdentry.u.index != EXECCMD)
813 popredir();
814 if (flags == EV_BACKCMD) {
815 backcmd->buf = memout.buf;
816 backcmd->nleft = memout.nextc - memout.buf;
817 memout.buf = NULL;
818 }
819 } else {
820 trputs("normal command: "); trargs(argv);
821 clearredir();
822 redirect(cmd->ncmd.redirect, 0);
823 if (varlist.list) {
824 p = stalloc(strlen(pathval()) + 1);
825 scopy(pathval(), p);
826 } else {
827 p = pathval();
828 }
829 for (sp = varlist.list ; sp ; sp = sp->next)
830 setvareq(sp->text, VEXPORT|VSTACK);
831 envp = environment();
832 shellexec(argv, envp, p, cmdentry.u.index);
833 /*NOTREACHED*/
834 }
835 goto out;
836
837 parent: /* parent process gets here (if we forked) */
838 if (mode == 0) { /* argument to fork */
839 INTOFF;
840 exitstatus = waitforjob(jp);
841 INTON;
842 } else if (mode == 2) {
843 backcmd->fd = pip[0];
844 close(pip[1]);
845 backcmd->jp = jp;
846 }
847
848 out:
849 if (lastarg)
850 setvar("_", lastarg, 0);
851 popstackmark(&smark);
852 }
853
854
855
856 /*
857 * Search for a command. This is called before we fork so that the
858 * location of the command will be available in the parent as well as
859 * the child. The check for "goodname" is an overly conservative
860 * check that the name will not be subject to expansion.
861 */
862
863 STATIC void
864 prehash(n)
865 union node *n;
866 {
867 struct cmdentry entry;
868
869 if (n->type == NCMD && goodname(n->ncmd.args->narg.text))
870 find_command(n->ncmd.args->narg.text, &entry, 0);
871 }
872
873
874
875 /*
876 * Builtin commands. Builtin commands whose functions are closely
877 * tied to evaluation are implemented here.
878 */
879
880 /*
881 * No command given, or a bltin command with no arguments. Set the
882 * specified variables.
883 */
884
885 bltincmd(argc, argv) char **argv; {
886 listsetvar(cmdenviron);
887 return 0;
888 }
889
890
891 /*
892 * Handle break and continue commands. Break, continue, and return are
893 * all handled by setting the evalskip flag. The evaluation routines
894 * above all check this flag, and if it is set they start skipping
895 * commands rather than executing them. The variable skipcount is
896 * the number of loops to break/continue, or the number of function
897 * levels to return. (The latter is always 1.) It should probably
898 * be an error to break out of more loops than exist, but it isn't
899 * in the standard shell so we don't make it one here.
900 */
901
902 breakcmd(argc, argv) char **argv; {
903 int n;
904
905 n = 1;
906 if (argc > 1)
907 n = number(argv[1]);
908 if (n > loopnest)
909 n = loopnest;
910 if (n > 0) {
911 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
912 skipcount = n;
913 }
914 return 0;
915 }
916
917
918 /*
919 * The return command.
920 */
921
922 returncmd(argc, argv) char **argv; {
923 int ret;
924
925 ret = exitstatus;
926 if (argc > 1)
927 ret = number(argv[1]);
928 if (funcnest) {
929 evalskip = SKIPFUNC;
930 skipcount = 1;
931 }
932 return ret;
933 }
934
935
936 falsecmd(argc, argv) char **argv; {
937 return 1;
938 }
939
940
941 truecmd(argc, argv) char **argv; {
942 return 0;
943 }
944
945
946 execcmd(argc, argv) char **argv; {
947 if (argc > 1) {
948 iflag = 0; /* exit on error */
949 mflag = 0;
950 optschanged();
951 shellexec(argv + 1, environment(), pathval(), 0);
952
953 }
954 return 0;
955 }
956