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