source: trunk/minix/commands/ash/eval.c@ 11

Last change on this file since 11 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

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