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