Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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