]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - bin/sh/eval.c
MFS r217050: Make minidumps work on i386/XEN.
[FreeBSD/releng/8.2.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  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)eval.c      8.9 (Berkeley) 6/8/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <paths.h>
42 #include <signal.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <sys/resource.h>
46 #include <sys/wait.h> /* For WIFSIGNALED(status) */
47 #include <errno.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 int evalskip;                   /* set if we are skipping commands */
78 static int skipcount;           /* number of levels to skip */
79 MKINIT int loopnest;            /* current loop nesting level */
80 int funcnest;                   /* depth of function calls */
81 static int builtin_flags;       /* evalcommand flags for builtins */
82
83
84 char *commandname;
85 struct strlist *cmdenviron;
86 int exitstatus;                 /* exit status of last command */
87 int oexitstatus;                /* saved exit status */
88
89
90 static void evalloop(union node *, int);
91 static void evalfor(union node *, int);
92 static void evalcase(union node *, int);
93 static void evalsubshell(union node *, int);
94 static void expredir(union node *);
95 static void evalpipe(union node *);
96 static void evalcommand(union node *, int, struct backcmd *);
97 static void prehash(union node *);
98
99
100 /*
101  * Called to reset things after an exception.
102  */
103
104 #ifdef mkinit
105 INCLUDE "eval.h"
106
107 RESET {
108         evalskip = 0;
109         loopnest = 0;
110         funcnest = 0;
111 }
112
113 SHELLPROC {
114         exitstatus = 0;
115 }
116 #endif
117
118
119
120 /*
121  * The eval command.
122  */
123
124 int
125 evalcmd(int argc, char **argv)
126 {
127         char *p;
128         char *concat;
129         char **ap;
130
131         if (argc > 1) {
132                 p = argv[1];
133                 if (argc > 2) {
134                         STARTSTACKSTR(concat);
135                         ap = argv + 2;
136                         for (;;) {
137                                 while (*p)
138                                         STPUTC(*p++, concat);
139                                 if ((p = *ap++) == NULL)
140                                         break;
141                                 STPUTC(' ', concat);
142                         }
143                         STPUTC('\0', concat);
144                         p = grabstackstr(concat);
145                 }
146                 evalstring(p, builtin_flags & EV_TESTED);
147         }
148         return exitstatus;
149 }
150
151
152 /*
153  * Execute a command or commands contained in a string.
154  */
155
156 void
157 evalstring(char *s, int flags)
158 {
159         union node *n;
160         struct stackmark smark;
161         int flags_exit;
162
163         flags_exit = flags & EV_EXIT;
164         flags &= ~EV_EXIT;
165         setstackmark(&smark);
166         setinputstring(s, 1);
167         while ((n = parsecmd(0)) != NEOF) {
168                 if (n != NULL) {
169                         if (flags_exit && preadateof())
170                                 evaltree(n, flags | EV_EXIT);
171                         else
172                                 evaltree(n, flags);
173                 }
174                 popstackmark(&smark);
175         }
176         popfile();
177         popstackmark(&smark);
178         if (flags_exit)
179                 exitshell(exitstatus);
180 }
181
182
183 /*
184  * Evaluate a parse tree.  The value is left in the global variable
185  * exitstatus.
186  */
187
188 void
189 evaltree(union node *n, int flags)
190 {
191         int do_etest;
192
193         do_etest = 0;
194         if (n == NULL) {
195                 TRACE(("evaltree(NULL) called\n"));
196                 exitstatus = 0;
197                 goto out;
198         }
199 #ifndef NO_HISTORY
200         displayhist = 1;        /* show history substitutions done with fc */
201 #endif
202         TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
203         switch (n->type) {
204         case NSEMI:
205                 evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
206                 if (evalskip)
207                         goto out;
208                 evaltree(n->nbinary.ch2, flags);
209                 break;
210         case NAND:
211                 evaltree(n->nbinary.ch1, EV_TESTED);
212                 if (evalskip || exitstatus != 0) {
213                         goto out;
214                 }
215                 evaltree(n->nbinary.ch2, flags);
216                 break;
217         case NOR:
218                 evaltree(n->nbinary.ch1, EV_TESTED);
219                 if (evalskip || exitstatus == 0)
220                         goto out;
221                 evaltree(n->nbinary.ch2, flags);
222                 break;
223         case NREDIR:
224                 expredir(n->nredir.redirect);
225                 redirect(n->nredir.redirect, REDIR_PUSH);
226                 evaltree(n->nredir.n, flags);
227                 popredir();
228                 break;
229         case NSUBSHELL:
230                 evalsubshell(n, flags);
231                 do_etest = !(flags & EV_TESTED);
232                 break;
233         case NBACKGND:
234                 evalsubshell(n, flags);
235                 break;
236         case NIF: {
237                 evaltree(n->nif.test, EV_TESTED);
238                 if (evalskip)
239                         goto out;
240                 if (exitstatus == 0)
241                         evaltree(n->nif.ifpart, flags);
242                 else if (n->nif.elsepart)
243                         evaltree(n->nif.elsepart, flags);
244                 else
245                         exitstatus = 0;
246                 break;
247         }
248         case NWHILE:
249         case NUNTIL:
250                 evalloop(n, flags & ~EV_EXIT);
251                 break;
252         case NFOR:
253                 evalfor(n, flags & ~EV_EXIT);
254                 break;
255         case NCASE:
256                 evalcase(n, flags);
257                 break;
258         case NDEFUN:
259                 defun(n->narg.text, n->narg.next);
260                 exitstatus = 0;
261                 break;
262         case NNOT:
263                 evaltree(n->nnot.com, EV_TESTED);
264                 exitstatus = !exitstatus;
265                 break;
266
267         case NPIPE:
268                 evalpipe(n);
269                 do_etest = !(flags & EV_TESTED);
270                 break;
271         case NCMD:
272                 evalcommand(n, flags, (struct backcmd *)NULL);
273                 do_etest = !(flags & EV_TESTED);
274                 break;
275         default:
276                 out1fmt("Node type = %d\n", n->type);
277                 flushout(&output);
278                 break;
279         }
280 out:
281         if (pendingsigs)
282                 dotrap();
283         if ((flags & EV_EXIT) || (eflag && exitstatus != 0 && do_etest))
284                 exitshell(exitstatus);
285 }
286
287
288 static void
289 evalloop(union node *n, int flags)
290 {
291         int status;
292
293         loopnest++;
294         status = 0;
295         for (;;) {
296                 evaltree(n->nbinary.ch1, EV_TESTED);
297                 if (evalskip) {
298 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
299                                 evalskip = 0;
300                                 continue;
301                         }
302                         if (evalskip == SKIPBREAK && --skipcount <= 0)
303                                 evalskip = 0;
304                         break;
305                 }
306                 if (n->type == NWHILE) {
307                         if (exitstatus != 0)
308                                 break;
309                 } else {
310                         if (exitstatus == 0)
311                                 break;
312                 }
313                 evaltree(n->nbinary.ch2, flags);
314                 status = exitstatus;
315                 if (evalskip)
316                         goto skipping;
317         }
318         loopnest--;
319         exitstatus = status;
320 }
321
322
323
324 static void
325 evalfor(union node *n, int flags)
326 {
327         struct arglist arglist;
328         union node *argp;
329         struct strlist *sp;
330         struct stackmark smark;
331
332         setstackmark(&smark);
333         arglist.lastp = &arglist.list;
334         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
335                 oexitstatus = exitstatus;
336                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
337                 if (evalskip)
338                         goto out;
339         }
340         *arglist.lastp = NULL;
341
342         exitstatus = 0;
343         loopnest++;
344         for (sp = arglist.list ; sp ; sp = sp->next) {
345                 setvar(n->nfor.var, sp->text, 0);
346                 evaltree(n->nfor.body, flags);
347                 if (evalskip) {
348                         if (evalskip == SKIPCONT && --skipcount <= 0) {
349                                 evalskip = 0;
350                                 continue;
351                         }
352                         if (evalskip == SKIPBREAK && --skipcount <= 0)
353                                 evalskip = 0;
354                         break;
355                 }
356         }
357         loopnest--;
358 out:
359         popstackmark(&smark);
360 }
361
362
363
364 static void
365 evalcase(union node *n, int flags)
366 {
367         union node *cp;
368         union node *patp;
369         struct arglist arglist;
370         struct stackmark smark;
371
372         setstackmark(&smark);
373         arglist.lastp = &arglist.list;
374         oexitstatus = exitstatus;
375         exitstatus = 0;
376         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
377         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
378                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
379                         if (casematch(patp, arglist.list->text)) {
380                                 if (evalskip == 0) {
381                                         evaltree(cp->nclist.body, flags);
382                                 }
383                                 goto out;
384                         }
385                 }
386         }
387 out:
388         popstackmark(&smark);
389 }
390
391
392
393 /*
394  * Kick off a subshell to evaluate a tree.
395  */
396
397 static void
398 evalsubshell(union node *n, int flags)
399 {
400         struct job *jp;
401         int backgnd = (n->type == NBACKGND);
402
403         expredir(n->nredir.redirect);
404         if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
405                         forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
406                 if (backgnd)
407                         flags &=~ EV_TESTED;
408                 redirect(n->nredir.redirect, 0);
409                 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
410         } else if (! backgnd) {
411                 INTOFF;
412                 exitstatus = waitforjob(jp, (int *)NULL);
413                 INTON;
414         }
415 }
416
417
418
419 /*
420  * Compute the names of the files in a redirection list.
421  */
422
423 static void
424 expredir(union node *n)
425 {
426         union node *redir;
427
428         for (redir = n ; redir ; redir = redir->nfile.next) {
429                 struct arglist fn;
430                 fn.lastp = &fn.list;
431                 oexitstatus = exitstatus;
432                 switch (redir->type) {
433                 case NFROM:
434                 case NTO:
435                 case NFROMTO:
436                 case NAPPEND:
437                 case NCLOBBER:
438                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
439                         redir->nfile.expfname = fn.list->text;
440                         break;
441                 case NFROMFD:
442                 case NTOFD:
443                         if (redir->ndup.vname) {
444                                 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
445                                 fixredir(redir, fn.list->text, 1);
446                         }
447                         break;
448                 }
449         }
450 }
451
452
453
454 /*
455  * Evaluate a pipeline.  All the processes in the pipeline are children
456  * of the process creating the pipeline.  (This differs from some versions
457  * of the shell, which make the last process in a pipeline the parent
458  * of all the rest.)
459  */
460
461 static void
462 evalpipe(union node *n)
463 {
464         struct job *jp;
465         struct nodelist *lp;
466         int pipelen;
467         int prevfd;
468         int pip[2];
469
470         TRACE(("evalpipe(%p) called\n", (void *)n));
471         pipelen = 0;
472         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
473                 pipelen++;
474         INTOFF;
475         jp = makejob(n, pipelen);
476         prevfd = -1;
477         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
478                 prehash(lp->n);
479                 pip[1] = -1;
480                 if (lp->next) {
481                         if (pipe(pip) < 0) {
482                                 close(prevfd);
483                                 error("Pipe call failed: %s", strerror(errno));
484                         }
485                 }
486                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
487                         INTON;
488                         if (prevfd > 0) {
489                                 dup2(prevfd, 0);
490                                 close(prevfd);
491                         }
492                         if (pip[1] >= 0) {
493                                 if (!(prevfd >= 0 && pip[0] == 0))
494                                         close(pip[0]);
495                                 if (pip[1] != 1) {
496                                         dup2(pip[1], 1);
497                                         close(pip[1]);
498                                 }
499                         }
500                         evaltree(lp->n, EV_EXIT);
501                 }
502                 if (prevfd >= 0)
503                         close(prevfd);
504                 prevfd = pip[0];
505                 close(pip[1]);
506         }
507         INTON;
508         if (n->npipe.backgnd == 0) {
509                 INTOFF;
510                 exitstatus = waitforjob(jp, (int *)NULL);
511                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
512                 INTON;
513         }
514 }
515
516
517
518 /*
519  * Execute a command inside back quotes.  If it's a builtin command, we
520  * want to save its output in a block obtained from malloc.  Otherwise
521  * we fork off a subprocess and get the output of the command via a pipe.
522  * Should be called with interrupts off.
523  */
524
525 void
526 evalbackcmd(union node *n, struct backcmd *result)
527 {
528         int pip[2];
529         struct job *jp;
530         struct stackmark smark;         /* unnecessary */
531
532         setstackmark(&smark);
533         result->fd = -1;
534         result->buf = NULL;
535         result->nleft = 0;
536         result->jp = NULL;
537         if (n == NULL) {
538                 exitstatus = 0;
539                 goto out;
540         }
541         if (n->type == NCMD) {
542                 exitstatus = oexitstatus;
543                 evalcommand(n, EV_BACKCMD, result);
544         } else {
545                 exitstatus = 0;
546                 if (pipe(pip) < 0)
547                         error("Pipe call failed: %s", strerror(errno));
548                 jp = makejob(n, 1);
549                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
550                         FORCEINTON;
551                         close(pip[0]);
552                         if (pip[1] != 1) {
553                                 dup2(pip[1], 1);
554                                 close(pip[1]);
555                         }
556                         evaltree(n, EV_EXIT);
557                 }
558                 close(pip[1]);
559                 result->fd = pip[0];
560                 result->jp = jp;
561         }
562 out:
563         popstackmark(&smark);
564         TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
565                 result->fd, result->buf, result->nleft, result->jp));
566 }
567
568
569
570 /*
571  * Execute a simple command.
572  */
573
574 static void
575 evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
576 {
577         struct stackmark smark;
578         union node *argp;
579         struct arglist arglist;
580         struct arglist varlist;
581         char **argv;
582         int argc;
583         char **envp;
584         int varflag;
585         struct strlist *sp;
586         int mode;
587         int pip[2];
588         struct cmdentry cmdentry;
589         struct job *jp;
590         struct jmploc jmploc;
591         struct jmploc *savehandler;
592         char *savecmdname;
593         struct shparam saveparam;
594         struct localvar *savelocalvars;
595         volatile int e;
596         char *lastarg;
597         int realstatus;
598         int do_clearcmdentry;
599
600         /* First expand the arguments. */
601         TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
602         setstackmark(&smark);
603         arglist.lastp = &arglist.list;
604         varlist.lastp = &varlist.list;
605         varflag = 1;
606         do_clearcmdentry = 0;
607         oexitstatus = exitstatus;
608         exitstatus = 0;
609         for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
610                 char *p = argp->narg.text;
611                 if (varflag && is_name(*p)) {
612                         do {
613                                 p++;
614                         } while (is_in_name(*p));
615                         if (*p == '=') {
616                                 expandarg(argp, &varlist, EXP_VARTILDE);
617                                 continue;
618                         }
619                 }
620                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
621                 varflag = 0;
622         }
623         *arglist.lastp = NULL;
624         *varlist.lastp = NULL;
625         expredir(cmd->ncmd.redirect);
626         argc = 0;
627         for (sp = arglist.list ; sp ; sp = sp->next)
628                 argc++;
629         argv = stalloc(sizeof (char *) * (argc + 1));
630
631         for (sp = arglist.list ; sp ; sp = sp->next) {
632                 TRACE(("evalcommand arg: %s\n", sp->text));
633                 *argv++ = sp->text;
634         }
635         *argv = NULL;
636         lastarg = NULL;
637         if (iflag && funcnest == 0 && argc > 0)
638                 lastarg = argv[-1];
639         argv -= argc;
640
641         /* Print the command if xflag is set. */
642         if (xflag) {
643                 char sep = 0;
644                 const char *p;
645                 out2str(ps4val());
646                 for (sp = varlist.list ; sp ; sp = sp->next) {
647                         if (sep != 0)
648                                 outc(' ', &errout);
649                         p = sp->text;
650                         while (*p != '=' && *p != '\0')
651                                 out2c(*p++);
652                         if (*p != '\0') {
653                                 out2c(*p++);
654                                 out2qstr(p);
655                         }
656                         sep = ' ';
657                 }
658                 for (sp = arglist.list ; sp ; sp = sp->next) {
659                         if (sep != 0)
660                                 outc(' ', &errout);
661                         /* Disambiguate command looking like assignment. */
662                         if (sp == arglist.list &&
663                                         strchr(sp->text, '=') != NULL &&
664                                         strchr(sp->text, '\'') == NULL) {
665                                 out2c('\'');
666                                 out2str(sp->text);
667                                 out2c('\'');
668                         } else
669                                 out2qstr(sp->text);
670                         sep = ' ';
671                 }
672                 outc('\n', &errout);
673                 flushout(&errout);
674         }
675
676         /* Now locate the command. */
677         if (argc == 0) {
678                 /* Variable assignment(s) without command */
679                 cmdentry.cmdtype = CMDBUILTIN;
680                 cmdentry.u.index = BLTINCMD;
681                 cmdentry.special = 1;
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                                  * directories 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,
728                                     &cmdentry.special)) < 0) {
729                                         outfmt(&errout, "%s: not found\n", *argv);
730                                         exitstatus = 127;
731                                         flushout(&errout);
732                                         return;
733                                 }
734                                 if (cmdentry.u.index != BLTINCMD)
735                                         break;
736                         }
737                 }
738         }
739
740         /* Fork off a child process if necessary. */
741         if (cmd->ncmd.backgnd
742          || (cmdentry.cmdtype == CMDNORMAL
743             && ((flags & EV_EXIT) == 0 || have_traps()))
744          || ((flags & EV_BACKCMD) != 0
745             && (cmdentry.cmdtype != CMDBUILTIN
746                  || cmdentry.u.index == CDCMD
747                  || cmdentry.u.index == DOTCMD
748                  || cmdentry.u.index == EVALCMD))
749          || (cmdentry.cmdtype == CMDBUILTIN &&
750             cmdentry.u.index == COMMANDCMD)) {
751                 jp = makejob(cmd, 1);
752                 mode = cmd->ncmd.backgnd;
753                 if (flags & EV_BACKCMD) {
754                         mode = FORK_NOJOB;
755                         if (pipe(pip) < 0)
756                                 error("Pipe call failed: %s", strerror(errno));
757                 }
758                 if (forkshell(jp, cmd, mode) != 0)
759                         goto parent;    /* at end of routine */
760                 if (flags & EV_BACKCMD) {
761                         FORCEINTON;
762                         close(pip[0]);
763                         if (pip[1] != 1) {
764                                 dup2(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                 reffunc(cmdentry.u.func);
788                 INTON;
789                 savehandler = handler;
790                 if (setjmp(jmploc.loc)) {
791                         if (exception == EXSHELLPROC)
792                                 freeparam(&saveparam);
793                         else {
794                                 freeparam(&shellparam);
795                                 shellparam = saveparam;
796                         }
797                         unreffunc(cmdentry.u.func);
798                         poplocalvars();
799                         localvars = savelocalvars;
800                         handler = savehandler;
801                         longjmp(handler->loc, 1);
802                 }
803                 handler = &jmploc;
804                 for (sp = varlist.list ; sp ; sp = sp->next)
805                         mklocal(sp->text);
806                 funcnest++;
807                 exitstatus = oexitstatus;
808                 if (flags & EV_TESTED)
809                         evaltree(getfuncnode(cmdentry.u.func), EV_TESTED);
810                 else
811                         evaltree(getfuncnode(cmdentry.u.func), 0);
812                 funcnest--;
813                 INTOFF;
814                 unreffunc(cmdentry.u.func);
815                 poplocalvars();
816                 localvars = savelocalvars;
817                 freeparam(&shellparam);
818                 shellparam = saveparam;
819                 handler = savehandler;
820                 popredir();
821                 INTON;
822                 if (evalskip == SKIPFUNC) {
823                         evalskip = 0;
824                         skipcount = 0;
825                 }
826                 if (flags & EV_EXIT)
827                         exitshell(exitstatus);
828         } else if (cmdentry.cmdtype == CMDBUILTIN) {
829 #ifdef DEBUG
830                 trputs("builtin command:  ");  trargs(argv);
831 #endif
832                 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
833                 if (flags == EV_BACKCMD) {
834                         memout.nleft = 0;
835                         memout.nextc = memout.buf;
836                         memout.bufsize = 64;
837                         mode |= REDIR_BACKQ;
838                 }
839                 savecmdname = commandname;
840                 cmdenviron = varlist.list;
841                 e = -1;
842                 savehandler = handler;
843                 if (setjmp(jmploc.loc)) {
844                         e = exception;
845                         exitstatus = (e == EXINT)? SIGINT+128 : 2;
846                         goto cmddone;
847                 }
848                 handler = &jmploc;
849                 redirect(cmd->ncmd.redirect, mode);
850                 if (cmdentry.special)
851                         listsetvar(cmdenviron);
852                 commandname = argv[0];
853                 argptr = argv + 1;
854                 nextopt_optptr = NULL;          /* initialize nextopt */
855                 builtin_flags = flags;
856                 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
857                 flushall();
858 cmddone:
859                 cmdenviron = NULL;
860                 out1 = &output;
861                 out2 = &errout;
862                 freestdout();
863                 if (e != EXSHELLPROC) {
864                         commandname = savecmdname;
865                         if (flags & EV_EXIT) {
866                                 exitshell(exitstatus);
867                         }
868                 }
869                 handler = savehandler;
870                 if (e != -1) {
871                         if ((e != EXERROR && e != EXEXEC)
872                             || cmdentry.special)
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 == FORK_FG) {  /* 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 == FORK_NOJOB) {
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 && 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.
949  */
950
951 int
952 bltincmd(int argc __unused, char **argv __unused)
953 {
954         /*
955          * Preserve exitstatus of a previous possible redirection
956          * as POSIX mandates
957          */
958         return exitstatus;
959 }
960
961
962 /*
963  * Handle break and continue commands.  Break, continue, and return are
964  * all handled by setting the evalskip flag.  The evaluation routines
965  * above all check this flag, and if it is set they start skipping
966  * commands rather than executing them.  The variable skipcount is
967  * the number of loops to break/continue, or the number of function
968  * levels to return.  (The latter is always 1.)  It should probably
969  * be an error to break out of more loops than exist, but it isn't
970  * in the standard shell so we don't make it one here.
971  */
972
973 int
974 breakcmd(int argc, char **argv)
975 {
976         int n = argc > 1 ? number(argv[1]) : 1;
977
978         if (n > loopnest)
979                 n = loopnest;
980         if (n > 0) {
981                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
982                 skipcount = n;
983         }
984         return 0;
985 }
986
987 /*
988  * The `command' command.
989  */
990 int
991 commandcmd(int argc, char **argv)
992 {
993         static char stdpath[] = _PATH_STDPATH;
994         struct jmploc loc, *old;
995         struct strlist *sp;
996         char *path;
997         int ch;
998         int cmd = -1;
999
1000         for (sp = cmdenviron; sp ; sp = sp->next)
1001                 setvareq(sp->text, VEXPORT|VSTACK);
1002         path = pathval();
1003
1004         optind = optreset = 1;
1005         opterr = 0;
1006         while ((ch = getopt(argc, argv, "pvV")) != -1) {
1007                 switch (ch) {
1008                 case 'p':
1009                         path = stdpath;
1010                         break;
1011                 case 'v':
1012                         cmd = TYPECMD_SMALLV;
1013                         break;
1014                 case 'V':
1015                         cmd = TYPECMD_BIGV;
1016                         break;
1017                 case '?':
1018                 default:
1019                         error("unknown option: -%c", optopt);
1020                 }
1021         }
1022         argc -= optind;
1023         argv += optind;
1024
1025         if (cmd != -1) {
1026                 if (argc != 1)
1027                         error("wrong number of arguments");
1028                 return typecmd_impl(2, argv - 1, cmd);
1029         }
1030         if (argc != 0) {
1031                 old = handler;
1032                 handler = &loc;
1033                 if (setjmp(handler->loc) == 0)
1034                         shellexec(argv, environment(), path, 0);
1035                 handler = old;
1036                 if (exception == EXEXEC)
1037                         exit(exerrno);
1038                 exraise(exception);
1039         }
1040
1041         /*
1042          * Do nothing successfully if no command was specified;
1043          * ksh also does this.
1044          */
1045         exit(0);
1046 }
1047
1048
1049 /*
1050  * The return command.
1051  */
1052
1053 int
1054 returncmd(int argc, char **argv)
1055 {
1056         int ret = argc > 1 ? number(argv[1]) : oexitstatus;
1057
1058         if (funcnest) {
1059                 evalskip = SKIPFUNC;
1060                 skipcount = 1;
1061         } else {
1062                 /* skip the rest of the file */
1063                 evalskip = SKIPFILE;
1064                 skipcount = 1;
1065         }
1066         return ret;
1067 }
1068
1069
1070 int
1071 falsecmd(int argc __unused, char **argv __unused)
1072 {
1073         return 1;
1074 }
1075
1076
1077 int
1078 truecmd(int argc __unused, char **argv __unused)
1079 {
1080         return 0;
1081 }
1082
1083
1084 int
1085 execcmd(int argc, char **argv)
1086 {
1087         if (argc > 1) {
1088                 struct strlist *sp;
1089
1090                 iflag = 0;              /* exit on error */
1091                 mflag = 0;
1092                 optschanged();
1093                 for (sp = cmdenviron; sp ; sp = sp->next)
1094                         setvareq(sp->text, VEXPORT|VSTACK);
1095                 shellexec(argv + 1, environment(), pathval(), 0);
1096
1097         }
1098         return 0;
1099 }
1100
1101
1102 int
1103 timescmd(int argc __unused, char **argv __unused)
1104 {
1105         struct rusage ru;
1106         long shumins, shsmins, chumins, chsmins;
1107         double shusecs, shssecs, chusecs, chssecs;
1108
1109         if (getrusage(RUSAGE_SELF, &ru) < 0)
1110                 return 1;
1111         shumins = ru.ru_utime.tv_sec / 60;
1112         shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1113         shsmins = ru.ru_stime.tv_sec / 60;
1114         shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1115         if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
1116                 return 1;
1117         chumins = ru.ru_utime.tv_sec / 60;
1118         chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1119         chsmins = ru.ru_stime.tv_sec / 60;
1120         chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1121         out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
1122             shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
1123         return 0;
1124 }