Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 22404 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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