Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show 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 /*-
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 }