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