Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/eval.c

Parent Directory Parent Directory | Revision Log Revision Log


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