]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - bin/sh/eval.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 MKINIT 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         }
411         if (! backgnd) {
412                 INTOFF;
413                 exitstatus = waitforjob(jp, (int *)NULL);
414                 INTON;
415         }
416 }
417
418
419
420 /*
421  * Compute the names of the files in a redirection list.
422  */
423
424 STATIC void
425 expredir(union node *n)
426 {
427         union node *redir;
428
429         for (redir = n ; redir ; redir = redir->nfile.next) {
430                 struct arglist fn;
431                 fn.lastp = &fn.list;
432                 oexitstatus = exitstatus;
433                 switch (redir->type) {
434                 case NFROM:
435                 case NTO:
436                 case NFROMTO:
437                 case NAPPEND:
438                 case NCLOBBER:
439                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
440                         redir->nfile.expfname = fn.list->text;
441                         break;
442                 case NFROMFD:
443                 case NTOFD:
444                         if (redir->ndup.vname) {
445                                 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
446                                 fixredir(redir, fn.list->text, 1);
447                         }
448                         break;
449                 }
450         }
451 }
452
453
454
455 /*
456  * Evaluate a pipeline.  All the processes in the pipeline are children
457  * of the process creating the pipeline.  (This differs from some versions
458  * of the shell, which make the last process in a pipeline the parent
459  * of all the rest.)
460  */
461
462 STATIC void
463 evalpipe(union node *n)
464 {
465         struct job *jp;
466         struct nodelist *lp;
467         int pipelen;
468         int prevfd;
469         int pip[2];
470
471         TRACE(("evalpipe(%p) called\n", (void *)n));
472         pipelen = 0;
473         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
474                 pipelen++;
475         INTOFF;
476         jp = makejob(n, pipelen);
477         prevfd = -1;
478         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
479                 prehash(lp->n);
480                 pip[1] = -1;
481                 if (lp->next) {
482                         if (pipe(pip) < 0) {
483                                 close(prevfd);
484                                 error("Pipe call failed: %s", strerror(errno));
485                         }
486                 }
487                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
488                         INTON;
489                         if (prevfd > 0) {
490                                 dup2(prevfd, 0);
491                                 close(prevfd);
492                         }
493                         if (pip[1] >= 0) {
494                                 if (!(prevfd >= 0 && pip[0] == 0))
495                                         close(pip[0]);
496                                 if (pip[1] != 1) {
497                                         dup2(pip[1], 1);
498                                         close(pip[1]);
499                                 }
500                         }
501                         evaltree(lp->n, EV_EXIT);
502                 }
503                 if (prevfd >= 0)
504                         close(prevfd);
505                 prevfd = pip[0];
506                 close(pip[1]);
507         }
508         INTON;
509         if (n->npipe.backgnd == 0) {
510                 INTOFF;
511                 exitstatus = waitforjob(jp, (int *)NULL);
512                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
513                 INTON;
514         }
515 }
516
517
518
519 /*
520  * Execute a command inside back quotes.  If it's a builtin command, we
521  * want to save its output in a block obtained from malloc.  Otherwise
522  * we fork off a subprocess and get the output of the command via a pipe.
523  * Should be called with interrupts off.
524  */
525
526 void
527 evalbackcmd(union node *n, struct backcmd *result)
528 {
529         int pip[2];
530         struct job *jp;
531         struct stackmark smark;         /* unnecessary */
532
533         setstackmark(&smark);
534         result->fd = -1;
535         result->buf = NULL;
536         result->nleft = 0;
537         result->jp = NULL;
538         if (n == NULL) {
539                 exitstatus = 0;
540                 goto out;
541         }
542         if (n->type == NCMD) {
543                 exitstatus = oexitstatus;
544                 evalcommand(n, EV_BACKCMD, result);
545         } else {
546                 exitstatus = 0;
547                 if (pipe(pip) < 0)
548                         error("Pipe call failed: %s", strerror(errno));
549                 jp = makejob(n, 1);
550                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
551                         FORCEINTON;
552                         close(pip[0]);
553                         if (pip[1] != 1) {
554                                 dup2(pip[1], 1);
555                                 close(pip[1]);
556                         }
557                         evaltree(n, EV_EXIT);
558                 }
559                 close(pip[1]);
560                 result->fd = pip[0];
561                 result->jp = jp;
562         }
563 out:
564         popstackmark(&smark);
565         TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
566                 result->fd, result->buf, result->nleft, result->jp));
567 }
568
569
570
571 /*
572  * Execute a simple command.
573  */
574
575 STATIC void
576 evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
577 {
578         struct stackmark smark;
579         union node *argp;
580         struct arglist arglist;
581         struct arglist varlist;
582         char **argv;
583         int argc;
584         char **envp;
585         int varflag;
586         struct strlist *sp;
587         int mode;
588         int pip[2];
589         struct cmdentry cmdentry;
590         struct job *jp;
591         struct jmploc jmploc;
592         struct jmploc *savehandler;
593         char *savecmdname;
594         struct shparam saveparam;
595         struct localvar *savelocalvars;
596         volatile int e;
597         char *lastarg;
598         int realstatus;
599         int do_clearcmdentry;
600
601         /* First expand the arguments. */
602         TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
603         setstackmark(&smark);
604         arglist.lastp = &arglist.list;
605         varlist.lastp = &varlist.list;
606         varflag = 1;
607         do_clearcmdentry = 0;
608         oexitstatus = exitstatus;
609         exitstatus = 0;
610         for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
611                 char *p = argp->narg.text;
612                 if (varflag && is_name(*p)) {
613                         do {
614                                 p++;
615                         } while (is_in_name(*p));
616                         if (*p == '=') {
617                                 expandarg(argp, &varlist, EXP_VARTILDE);
618                                 continue;
619                         }
620                 }
621                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
622                 varflag = 0;
623         }
624         *arglist.lastp = NULL;
625         *varlist.lastp = NULL;
626         expredir(cmd->ncmd.redirect);
627         argc = 0;
628         for (sp = arglist.list ; sp ; sp = sp->next)
629                 argc++;
630         argv = stalloc(sizeof (char *) * (argc + 1));
631
632         for (sp = arglist.list ; sp ; sp = sp->next) {
633                 TRACE(("evalcommand arg: %s\n", sp->text));
634                 *argv++ = sp->text;
635         }
636         *argv = NULL;
637         lastarg = NULL;
638         if (iflag && funcnest == 0 && argc > 0)
639                 lastarg = argv[-1];
640         argv -= argc;
641
642         /* Print the command if xflag is set. */
643         if (xflag) {
644                 char sep = 0;
645                 const char *p;
646                 out2str(ps4val());
647                 for (sp = varlist.list ; sp ; sp = sp->next) {
648                         if (sep != 0)
649                                 outc(' ', &errout);
650                         p = sp->text;
651                         while (*p != '=' && *p != '\0')
652                                 out2c(*p++);
653                         if (*p != '\0') {
654                                 out2c(*p++);
655                                 out2qstr(p);
656                         }
657                         sep = ' ';
658                 }
659                 for (sp = arglist.list ; sp ; sp = sp->next) {
660                         if (sep != 0)
661                                 outc(' ', &errout);
662                         /* Disambiguate command looking like assignment. */
663                         if (sp == arglist.list &&
664                                         strchr(sp->text, '=') != NULL &&
665                                         strchr(sp->text, '\'') == NULL) {
666                                 out2c('\'');
667                                 out2str(sp->text);
668                                 out2c('\'');
669                         } else
670                                 out2qstr(sp->text);
671                         sep = ' ';
672                 }
673                 outc('\n', &errout);
674                 flushout(&errout);
675         }
676
677         /* Now locate the command. */
678         if (argc == 0) {
679                 /* Variable assignment(s) without command */
680                 cmdentry.cmdtype = CMDBUILTIN;
681                 cmdentry.u.index = BLTINCMD;
682                 cmdentry.special = 1;
683         } else {
684                 static const char PATH[] = "PATH=";
685                 char *path = pathval();
686
687                 /*
688                  * Modify the command lookup path, if a PATH= assignment
689                  * is present
690                  */
691                 for (sp = varlist.list ; sp ; sp = sp->next)
692                         if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
693                                 path = sp->text + sizeof(PATH) - 1;
694                                 /*
695                                  * On `PATH=... command`, we need to make
696                                  * sure that the command isn't using the
697                                  * non-updated hash table of the outer PATH
698                                  * setting and we need to make sure that
699                                  * the hash table isn't filled with items
700                                  * from the temporary setting.
701                                  *
702                                  * It would be better to forbit using and
703                                  * updating the table while this command
704                                  * runs, by the command finding mechanism
705                                  * is heavily integrated with hash handling,
706                                  * so we just delete the hash before and after
707                                  * the command runs. Partly deleting like
708                                  * changepatch() does doesn't seem worth the
709                                  * bookinging effort, since most such runs add
710                                  * directories in front of the new PATH.
711                                  */
712                                 clearcmdentry(0);
713                                 do_clearcmdentry = 1;
714                         }
715
716                 find_command(argv[0], &cmdentry, 1, path);
717                 if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
718                         exitstatus = 127;
719                         flushout(&errout);
720                         return;
721                 }
722                 /* implement the bltin builtin here */
723                 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
724                         for (;;) {
725                                 argv++;
726                                 if (--argc == 0)
727                                         break;
728                                 if ((cmdentry.u.index = find_builtin(*argv,
729                                     &cmdentry.special)) < 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 || have_traps()))
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                                 dup2(pip[1], 1);
766                                 close(pip[1]);
767                         }
768                 }
769                 flags |= EV_EXIT;
770         }
771
772         /* This is the child process if a fork occurred. */
773         /* Execute the command. */
774         if (cmdentry.cmdtype == CMDFUNCTION) {
775 #ifdef DEBUG
776                 trputs("Shell function:  ");  trargs(argv);
777 #endif
778                 redirect(cmd->ncmd.redirect, REDIR_PUSH);
779                 saveparam = shellparam;
780                 shellparam.malloc = 0;
781                 shellparam.reset = 1;
782                 shellparam.nparam = argc - 1;
783                 shellparam.p = argv + 1;
784                 shellparam.optnext = NULL;
785                 INTOFF;
786                 savelocalvars = localvars;
787                 localvars = NULL;
788                 reffunc(cmdentry.u.func);
789                 INTON;
790                 savehandler = handler;
791                 if (setjmp(jmploc.loc)) {
792                         if (exception == EXSHELLPROC)
793                                 freeparam(&saveparam);
794                         else {
795                                 freeparam(&shellparam);
796                                 shellparam = saveparam;
797                         }
798                         unreffunc(cmdentry.u.func);
799                         poplocalvars();
800                         localvars = savelocalvars;
801                         handler = savehandler;
802                         longjmp(handler->loc, 1);
803                 }
804                 handler = &jmploc;
805                 for (sp = varlist.list ; sp ; sp = sp->next)
806                         mklocal(sp->text);
807                 funcnest++;
808                 exitstatus = oexitstatus;
809                 if (flags & EV_TESTED)
810                         evaltree(getfuncnode(cmdentry.u.func), EV_TESTED);
811                 else
812                         evaltree(getfuncnode(cmdentry.u.func), 0);
813                 funcnest--;
814                 INTOFF;
815                 unreffunc(cmdentry.u.func);
816                 poplocalvars();
817                 localvars = savelocalvars;
818                 freeparam(&shellparam);
819                 shellparam = saveparam;
820                 handler = savehandler;
821                 popredir();
822                 INTON;
823                 if (evalskip == SKIPFUNC) {
824                         evalskip = 0;
825                         skipcount = 0;
826                 }
827                 if (flags & EV_EXIT)
828                         exitshell(exitstatus);
829         } else if (cmdentry.cmdtype == CMDBUILTIN) {
830 #ifdef DEBUG
831                 trputs("builtin command:  ");  trargs(argv);
832 #endif
833                 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
834                 if (flags == EV_BACKCMD) {
835                         memout.nleft = 0;
836                         memout.nextc = memout.buf;
837                         memout.bufsize = 64;
838                         mode |= REDIR_BACKQ;
839                 }
840                 savecmdname = commandname;
841                 cmdenviron = varlist.list;
842                 e = -1;
843                 savehandler = handler;
844                 if (setjmp(jmploc.loc)) {
845                         e = exception;
846                         exitstatus = (e == EXINT)? SIGINT+128 : 2;
847                         goto cmddone;
848                 }
849                 handler = &jmploc;
850                 redirect(cmd->ncmd.redirect, mode);
851                 if (cmdentry.special)
852                         listsetvar(cmdenviron);
853                 commandname = argv[0];
854                 argptr = argv + 1;
855                 optptr = NULL;                  /* initialize nextopt */
856                 builtin_flags = flags;
857                 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
858                 flushall();
859 cmddone:
860                 cmdenviron = NULL;
861                 out1 = &output;
862                 out2 = &errout;
863                 freestdout();
864                 if (e != EXSHELLPROC) {
865                         commandname = savecmdname;
866                         if (flags & EV_EXIT) {
867                                 exitshell(exitstatus);
868                         }
869                 }
870                 handler = savehandler;
871                 if (e != -1) {
872                         if ((e != EXERROR && e != EXEXEC)
873                             || cmdentry.special)
874                                 exraise(e);
875                         FORCEINTON;
876                 }
877                 if (cmdentry.u.index != EXECCMD)
878                         popredir();
879                 if (flags == EV_BACKCMD) {
880                         backcmd->buf = memout.buf;
881                         backcmd->nleft = memout.nextc - memout.buf;
882                         memout.buf = NULL;
883                 }
884         } else {
885 #ifdef DEBUG
886                 trputs("normal command:  ");  trargs(argv);
887 #endif
888                 clearredir();
889                 redirect(cmd->ncmd.redirect, 0);
890                 for (sp = varlist.list ; sp ; sp = sp->next)
891                         setvareq(sp->text, VEXPORT|VSTACK);
892                 envp = environment();
893                 shellexec(argv, envp, pathval(), cmdentry.u.index);
894                 /*NOTREACHED*/
895         }
896         goto out;
897
898 parent: /* parent process gets here (if we forked) */
899         if (mode == 0) {        /* argument to fork */
900                 INTOFF;
901                 exitstatus = waitforjob(jp, &realstatus);
902                 INTON;
903                 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) {
904                         evalskip = SKIPBREAK;
905                         skipcount = loopnest;
906                 }
907         } else if (mode == 2) {
908                 backcmd->fd = pip[0];
909                 close(pip[1]);
910                 backcmd->jp = jp;
911         }
912
913 out:
914         if (lastarg)
915                 setvar("_", lastarg, 0);
916         if (do_clearcmdentry)
917                 clearcmdentry(0);
918         popstackmark(&smark);
919 }
920
921
922
923 /*
924  * Search for a command.  This is called before we fork so that the
925  * location of the command will be available in the parent as well as
926  * the child.  The check for "goodname" is an overly conservative
927  * check that the name will not be subject to expansion.
928  */
929
930 STATIC void
931 prehash(union node *n)
932 {
933         struct cmdentry entry;
934
935         if (n && n->type == NCMD && n->ncmd.args)
936                 if (goodname(n->ncmd.args->narg.text))
937                         find_command(n->ncmd.args->narg.text, &entry, 0,
938                                      pathval());
939 }
940
941
942
943 /*
944  * Builtin commands.  Builtin commands whose functions are closely
945  * tied to evaluation are implemented here.
946  */
947
948 /*
949  * No command given, or a bltin command with no arguments.
950  */
951
952 int
953 bltincmd(int argc __unused, char **argv __unused)
954 {
955         /*
956          * Preserve exitstatus of a previous possible redirection
957          * as POSIX mandates
958          */
959         return exitstatus;
960 }
961
962
963 /*
964  * Handle break and continue commands.  Break, continue, and return are
965  * all handled by setting the evalskip flag.  The evaluation routines
966  * above all check this flag, and if it is set they start skipping
967  * commands rather than executing them.  The variable skipcount is
968  * the number of loops to break/continue, or the number of function
969  * levels to return.  (The latter is always 1.)  It should probably
970  * be an error to break out of more loops than exist, but it isn't
971  * in the standard shell so we don't make it one here.
972  */
973
974 int
975 breakcmd(int argc, char **argv)
976 {
977         int n = argc > 1 ? number(argv[1]) : 1;
978
979         if (n > loopnest)
980                 n = loopnest;
981         if (n > 0) {
982                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
983                 skipcount = n;
984         }
985         return 0;
986 }
987
988 /*
989  * The `command' command.
990  */
991 int
992 commandcmd(int argc, char **argv)
993 {
994         static char stdpath[] = _PATH_STDPATH;
995         struct jmploc loc, *old;
996         struct strlist *sp;
997         char *path;
998         int ch;
999         int cmd = -1;
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, "pvV")) != -1) {
1008                 switch (ch) {
1009                 case 'p':
1010                         path = stdpath;
1011                         break;
1012                 case 'v':
1013                         cmd = TYPECMD_SMALLV;
1014                         break;
1015                 case 'V':
1016                         cmd = TYPECMD_BIGV;
1017                         break;
1018                 case '?':
1019                 default:
1020                         error("unknown option: -%c", optopt);
1021                 }
1022         }
1023         argc -= optind;
1024         argv += optind;
1025
1026         if (cmd != -1) {
1027                 if (argc != 1)
1028                         error("wrong number of arguments");
1029                 return typecmd_impl(2, argv - 1, cmd);
1030         }
1031         if (argc != 0) {
1032                 old = handler;
1033                 handler = &loc;
1034                 if (setjmp(handler->loc) == 0)
1035                         shellexec(argv, environment(), path, 0);
1036                 handler = old;
1037                 if (exception == EXEXEC)
1038                         exit(exerrno);
1039                 exraise(exception);
1040         }
1041
1042         /*
1043          * Do nothing successfully if no command was specified;
1044          * ksh also does this.
1045          */
1046         exit(0);
1047 }
1048
1049
1050 /*
1051  * The return command.
1052  */
1053
1054 int
1055 returncmd(int argc, char **argv)
1056 {
1057         int ret = argc > 1 ? number(argv[1]) : oexitstatus;
1058
1059         if (funcnest) {
1060                 evalskip = SKIPFUNC;
1061                 skipcount = 1;
1062         } else {
1063                 /* skip the rest of the file */
1064                 evalskip = SKIPFILE;
1065                 skipcount = 1;
1066         }
1067         return ret;
1068 }
1069
1070
1071 int
1072 falsecmd(int argc __unused, char **argv __unused)
1073 {
1074         return 1;
1075 }
1076
1077
1078 int
1079 truecmd(int argc __unused, char **argv __unused)
1080 {
1081         return 0;
1082 }
1083
1084
1085 int
1086 execcmd(int argc, char **argv)
1087 {
1088         if (argc > 1) {
1089                 struct strlist *sp;
1090
1091                 iflag = 0;              /* exit on error */
1092                 mflag = 0;
1093                 optschanged();
1094                 for (sp = cmdenviron; sp ; sp = sp->next)
1095                         setvareq(sp->text, VEXPORT|VSTACK);
1096                 shellexec(argv + 1, environment(), pathval(), 0);
1097
1098         }
1099         return 0;
1100 }
1101
1102
1103 int
1104 timescmd(int argc __unused, char **argv __unused)
1105 {
1106         struct rusage ru;
1107         long shumins, shsmins, chumins, chsmins;
1108         double shusecs, shssecs, chusecs, chssecs;
1109
1110         if (getrusage(RUSAGE_SELF, &ru) < 0)
1111                 return 1;
1112         shumins = ru.ru_utime.tv_sec / 60;
1113         shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1114         shsmins = ru.ru_stime.tv_sec / 60;
1115         shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1116         if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
1117                 return 1;
1118         chumins = ru.ru_utime.tv_sec / 60;
1119         chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1120         chsmins = ru.ru_stime.tv_sec / 60;
1121         chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1122         out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
1123             shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
1124         return 0;
1125 }