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