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