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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 40 #endif 41 static const char rcsid[] = 42 "$FreeBSD$"; 43 #endif /* not lint */ 44 45 #include <signal.h> 46 #include <unistd.h> 47 #include <sys/wait.h> /* For WIFSIGNALED(status) */ 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 /* flags in argument to evaltree */ 78 #define EV_EXIT 01 /* exit after evaluating tree */ 79 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 80 #define EV_BACKCMD 04 /* command executing within back quotes */ 81 82 MKINIT int evalskip; /* set if we are skipping commands */ 83 STATIC int skipcount; /* number of levels to skip */ 84 MKINIT int loopnest; /* current loop nesting level */ 85 int funcnest; /* depth of function calls */ 86 87 88 char *commandname; 89 struct strlist *cmdenviron; 90 int exitstatus; /* exit status of last command */ 91 int oexitstatus; /* saved exit status */ 92 93 94 STATIC void evalloop __P((union node *)); 95 STATIC void evalfor __P((union node *)); 96 STATIC void evalcase __P((union node *, int)); 97 STATIC void evalsubshell __P((union node *, int)); 98 STATIC void expredir __P((union node *)); 99 STATIC void evalpipe __P((union node *)); 100 STATIC void evalcommand __P((union node *, int, struct backcmd *)); 101 STATIC void prehash __P((union node *)); 102 103 104 /* 105 * Called to reset things after an exception. 106 */ 107 108 #ifdef mkinit 109 INCLUDE "eval.h" 110 111 RESET { 112 evalskip = 0; 113 loopnest = 0; 114 funcnest = 0; 115 } 116 117 SHELLPROC { 118 exitstatus = 0; 119 } 120 #endif 121 122 123 124 /* 125 * The eval command. 126 */ 127 128 int 129 evalcmd(argc, argv) 130 int argc; 131 char **argv; 132 { 133 char *p; 134 char *concat; 135 char **ap; 136 137 if (argc > 1) { 138 p = argv[1]; 139 if (argc > 2) { 140 STARTSTACKSTR(concat); 141 ap = argv + 2; 142 for (;;) { 143 while (*p) 144 STPUTC(*p++, concat); 145 if ((p = *ap++) == NULL) 146 break; 147 STPUTC(' ', concat); 148 } 149 STPUTC('\0', concat); 150 p = grabstackstr(concat); 151 } 152 evalstring(p); 153 } 154 return exitstatus; 155 } 156 157 158 /* 159 * Execute a command or commands contained in a string. 160 */ 161 162 void 163 evalstring(s) 164 char *s; 165 { 166 union node *n; 167 struct stackmark smark; 168 169 setstackmark(&smark); 170 setinputstring(s, 1); 171 while ((n = parsecmd(0)) != NEOF) { 172 evaltree(n, 0); 173 popstackmark(&smark); 174 } 175 popfile(); 176 popstackmark(&smark); 177 } 178 179 180 181 /* 182 * Evaluate a parse tree. The value is left in the global variable 183 * exitstatus. 184 */ 185 186 void 187 evaltree(n, flags) 188 union node *n; 189 int flags; 190 { 191 if (n == NULL) { 192 TRACE(("evaltree(NULL) called\n")); 193 exitstatus = 0; 194 goto out; 195 } 196 #ifndef NO_HISTORY 197 displayhist = 1; /* show history substitutions done with fc */ 198 #endif 199 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); 200 switch (n->type) { 201 case NSEMI: 202 evaltree(n->nbinary.ch1, 0); 203 if (evalskip) 204 goto out; 205 evaltree(n->nbinary.ch2, flags); 206 break; 207 case NAND: 208 evaltree(n->nbinary.ch1, EV_TESTED); 209 if (evalskip || exitstatus != 0) { 210 flags |= EV_TESTED; 211 goto out; 212 } 213 evaltree(n->nbinary.ch2, flags); 214 break; 215 case NOR: 216 evaltree(n->nbinary.ch1, EV_TESTED); 217 if (evalskip || exitstatus == 0) 218 goto out; 219 evaltree(n->nbinary.ch2, flags); 220 break; 221 case NREDIR: 222 expredir(n->nredir.redirect); 223 redirect(n->nredir.redirect, REDIR_PUSH); 224 evaltree(n->nredir.n, flags); 225 popredir(); 226 break; 227 case NSUBSHELL: 228 evalsubshell(n, flags); 229 break; 230 case NBACKGND: 231 evalsubshell(n, flags); 232 break; 233 case NIF: { 234 evaltree(n->nif.test, EV_TESTED); 235 if (evalskip) 236 goto out; 237 if (exitstatus == 0) 238 evaltree(n->nif.ifpart, flags); 239 else if (n->nif.elsepart) 240 evaltree(n->nif.elsepart, flags); 241 else 242 exitstatus = 0; 243 break; 244 } 245 case NWHILE: 246 case NUNTIL: 247 evalloop(n); 248 break; 249 case NFOR: 250 evalfor(n); 251 break; 252 case NCASE: 253 evalcase(n, flags); 254 break; 255 case NDEFUN: 256 defun(n->narg.text, n->narg.next); 257 exitstatus = 0; 258 break; 259 case NNOT: 260 evaltree(n->nnot.com, EV_TESTED); 261 exitstatus = !exitstatus; 262 break; 263 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 /* 279 * XXX - Like "!(n->type == NSEMI)", more types will probably 280 * need to be excluded from this test. It's probably better 281 * to set or unset EV_TESTED in the loop above than to bloat 282 * the conditional here. 283 */ 284 if ((flags & EV_EXIT) || (eflag && exitstatus 285 && !(flags & EV_TESTED) && !(n->type == NSEMI))) 286 exitshell(exitstatus); 287 } 288 289 290 STATIC void 291 evalloop(n) 292 union node *n; 293 { 294 int status; 295 296 loopnest++; 297 status = 0; 298 for (;;) { 299 evaltree(n->nbinary.ch1, EV_TESTED); 300 if (evalskip) { 301 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 302 evalskip = 0; 303 continue; 304 } 305 if (evalskip == SKIPBREAK && --skipcount <= 0) 306 evalskip = 0; 307 break; 308 } 309 if (n->type == NWHILE) { 310 if (exitstatus != 0) 311 break; 312 } else { 313 if (exitstatus == 0) 314 break; 315 } 316 evaltree(n->nbinary.ch2, 0); 317 status = exitstatus; 318 if (evalskip) 319 goto skipping; 320 } 321 loopnest--; 322 exitstatus = status; 323 } 324 325 326 327 STATIC void 328 evalfor(n) 329 union node *n; 330 { 331 struct arglist arglist; 332 union node *argp; 333 struct strlist *sp; 334 struct stackmark smark; 335 336 setstackmark(&smark); 337 arglist.lastp = &arglist.list; 338 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 339 oexitstatus = exitstatus; 340 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 341 if (evalskip) 342 goto out; 343 } 344 *arglist.lastp = NULL; 345 346 exitstatus = 0; 347 loopnest++; 348 for (sp = arglist.list ; sp ; sp = sp->next) { 349 setvar(n->nfor.var, sp->text, 0); 350 evaltree(n->nfor.body, 0); 351 if (evalskip) { 352 if (evalskip == SKIPCONT && --skipcount <= 0) { 353 evalskip = 0; 354 continue; 355 } 356 if (evalskip == SKIPBREAK && --skipcount <= 0) 357 evalskip = 0; 358 break; 359 } 360 } 361 loopnest--; 362 out: 363 popstackmark(&smark); 364 } 365 366 367 368 STATIC void 369 evalcase(n, flags) 370 union node *n; 371 int flags; 372 { 373 union node *cp; 374 union node *patp; 375 struct arglist arglist; 376 struct stackmark smark; 377 378 setstackmark(&smark); 379 arglist.lastp = &arglist.list; 380 oexitstatus = exitstatus; 381 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 382 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 383 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 384 if (casematch(patp, arglist.list->text)) { 385 if (evalskip == 0) { 386 evaltree(cp->nclist.body, flags); 387 } 388 goto out; 389 } 390 } 391 } 392 out: 393 popstackmark(&smark); 394 } 395 396 397 398 /* 399 * Kick off a subshell to evaluate a tree. 400 */ 401 402 STATIC void 403 evalsubshell(n, flags) 404 union node *n; 405 int flags; 406 { 407 struct job *jp; 408 int backgnd = (n->type == NBACKGND); 409 410 expredir(n->nredir.redirect); 411 jp = makejob(n, 1); 412 if (forkshell(jp, n, backgnd) == 0) { 413 if (backgnd) 414 flags &=~ EV_TESTED; 415 redirect(n->nredir.redirect, 0); 416 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 417 } 418 if (! backgnd) { 419 INTOFF; 420 exitstatus = waitforjob(jp, (int *)NULL); 421 INTON; 422 } 423 } 424 425 426 427 /* 428 * Compute the names of the files in a redirection list. 429 */ 430 431 STATIC void 432 expredir(n) 433 union node *n; 434 { 435 union node *redir; 436 437 for (redir = n ; redir ; redir = redir->nfile.next) { 438 struct arglist fn; 439 fn.lastp = &fn.list; 440 oexitstatus = exitstatus; 441 switch (redir->type) { 442 case NFROM: 443 case NTO: 444 case NAPPEND: 445 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 446 redir->nfile.expfname = fn.list->text; 447 break; 448 case NFROMFD: 449 case NTOFD: 450 if (redir->ndup.vname) { 451 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 452 fixredir(redir, fn.list->text, 1); 453 } 454 break; 455 } 456 } 457 } 458 459 460 461 /* 462 * Evaluate a pipeline. All the processes in the pipeline are children 463 * of the process creating the pipeline. (This differs from some versions 464 * of the shell, which make the last process in a pipeline the parent 465 * of all the rest.) 466 */ 467 468 STATIC void 469 evalpipe(n) 470 union node *n; 471 { 472 struct job *jp; 473 struct nodelist *lp; 474 int pipelen; 475 int prevfd; 476 int pip[2]; 477 478 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 479 pipelen = 0; 480 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 481 pipelen++; 482 INTOFF; 483 jp = makejob(n, pipelen); 484 prevfd = -1; 485 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 486 prehash(lp->n); 487 pip[1] = -1; 488 if (lp->next) { 489 if (pipe(pip) < 0) { 490 close(prevfd); 491 error("Pipe call failed"); 492 } 493 } 494 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 495 INTON; 496 if (prevfd > 0) { 497 close(0); 498 copyfd(prevfd, 0); 499 close(prevfd); 500 } 501 if (pip[1] >= 0) { 502 close(pip[0]); 503 if (pip[1] != 1) { 504 close(1); 505 copyfd(pip[1], 1); 506 close(pip[1]); 507 } 508 } 509 evaltree(lp->n, EV_EXIT); 510 } 511 if (prevfd >= 0) 512 close(prevfd); 513 prevfd = pip[0]; 514 close(pip[1]); 515 } 516 INTON; 517 if (n->npipe.backgnd == 0) { 518 INTOFF; 519 exitstatus = waitforjob(jp, (int *)NULL); 520 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 521 INTON; 522 } 523 } 524 525 526 527 /* 528 * Execute a command inside back quotes. If it's a builtin command, we 529 * want to save its output in a block obtained from malloc. Otherwise 530 * we fork off a subprocess and get the output of the command via a pipe. 531 * Should be called with interrupts off. 532 */ 533 534 void 535 evalbackcmd(n, result) 536 union node *n; 537 struct backcmd *result; 538 { 539 int pip[2]; 540 struct job *jp; 541 struct stackmark smark; /* unnecessary */ 542 543 setstackmark(&smark); 544 result->fd = -1; 545 result->buf = NULL; 546 result->nleft = 0; 547 result->jp = NULL; 548 if (n == NULL) { 549 exitstatus = 0; 550 goto out; 551 } 552 if (n->type == NCMD) { 553 exitstatus = oexitstatus; 554 evalcommand(n, EV_BACKCMD, result); 555 } else { 556 exitstatus = 0; 557 if (pipe(pip) < 0) 558 error("Pipe call failed"); 559 jp = makejob(n, 1); 560 if (forkshell(jp, n, FORK_NOJOB) == 0) { 561 FORCEINTON; 562 close(pip[0]); 563 if (pip[1] != 1) { 564 close(1); 565 copyfd(pip[1], 1); 566 close(pip[1]); 567 } 568 evaltree(n, EV_EXIT); 569 } 570 close(pip[1]); 571 result->fd = pip[0]; 572 result->jp = jp; 573 } 574 out: 575 popstackmark(&smark); 576 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 577 result->fd, result->buf, result->nleft, result->jp)); 578 } 579 580 581 582 /* 583 * Execute a simple command. 584 */ 585 586 STATIC void 587 evalcommand(cmd, flags, backcmd) 588 union node *cmd; 589 int flags; 590 struct backcmd *backcmd; 591 { 592 struct stackmark smark; 593 union node *argp; 594 struct arglist arglist; 595 struct arglist varlist; 596 char **argv; 597 int argc; 598 char **envp; 599 int varflag; 600 struct strlist *sp; 601 int mode; 602 int pip[2]; 603 struct cmdentry cmdentry; 604 struct job *jp; 605 struct jmploc jmploc; 606 struct jmploc *volatile savehandler; 607 char *volatile savecmdname; 608 volatile struct shparam saveparam; 609 struct localvar *volatile savelocalvars; 610 volatile int e; 611 char *lastarg; 612 int realstatus; 613 #if __GNUC__ 614 /* Avoid longjmp clobbering */ 615 (void) &argv; 616 (void) &argc; 617 (void) &lastarg; 618 (void) &flags; 619 #endif 620 621 /* First expand the arguments. */ 622 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 623 setstackmark(&smark); 624 arglist.lastp = &arglist.list; 625 varlist.lastp = &varlist.list; 626 varflag = 1; 627 oexitstatus = exitstatus; 628 exitstatus = 0; 629 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 630 char *p = argp->narg.text; 631 if (varflag && is_name(*p)) { 632 do { 633 p++; 634 } while (is_in_name(*p)); 635 if (*p == '=') { 636 expandarg(argp, &varlist, EXP_VARTILDE); 637 continue; 638 } 639 } 640 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 641 varflag = 0; 642 } 643 *arglist.lastp = NULL; 644 *varlist.lastp = NULL; 645 expredir(cmd->ncmd.redirect); 646 argc = 0; 647 for (sp = arglist.list ; sp ; sp = sp->next) 648 argc++; 649 argv = stalloc(sizeof (char *) * (argc + 1)); 650 651 for (sp = arglist.list ; sp ; sp = sp->next) { 652 TRACE(("evalcommand arg: %s\n", sp->text)); 653 *argv++ = sp->text; 654 } 655 *argv = NULL; 656 lastarg = NULL; 657 if (iflag && funcnest == 0 && argc > 0) 658 lastarg = argv[-1]; 659 argv -= argc; 660 661 /* Print the command if xflag is set. */ 662 if (xflag) { 663 outc('+', &errout); 664 for (sp = varlist.list ; sp ; sp = sp->next) { 665 outc(' ', &errout); 666 out2str(sp->text); 667 } 668 for (sp = arglist.list ; sp ; sp = sp->next) { 669 outc(' ', &errout); 670 out2str(sp->text); 671 } 672 outc('\n', &errout); 673 flushout(&errout); 674 } 675 676 /* Now locate the command. */ 677 if (argc == 0) { 678 cmdentry.cmdtype = CMDBUILTIN; 679 cmdentry.u.index = BLTINCMD; 680 } else { 681 static const char PATH[] = "PATH="; 682 char *path = pathval(); 683 684 /* 685 * Modify the command lookup path, if a PATH= assignment 686 * is present 687 */ 688 for (sp = varlist.list ; sp ; sp = sp->next) 689 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 690 path = sp->text + sizeof(PATH) - 1; 691 692 find_command(argv[0], &cmdentry, 1, path); 693 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 694 exitstatus = 127; 695 flushout(&errout); 696 return; 697 } 698 /* implement the bltin builtin here */ 699 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 700 for (;;) { 701 argv++; 702 if (--argc == 0) 703 break; 704 if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 705 outfmt(&errout, "%s: not found\n", *argv); 706 exitstatus = 127; 707 flushout(&errout); 708 return; 709 } 710 if (cmdentry.u.index != BLTINCMD) 711 break; 712 } 713 } 714 } 715 716 /* Fork off a child process if necessary. */ 717 if (cmd->ncmd.backgnd 718 || (cmdentry.cmdtype == CMDNORMAL 719 && ((flags & EV_EXIT) == 0 || Tflag)) 720 || ((flags & EV_BACKCMD) != 0 721 && (cmdentry.cmdtype != CMDBUILTIN 722 || cmdentry.u.index == CDCMD 723 || cmdentry.u.index == DOTCMD 724 || cmdentry.u.index == EVALCMD))) { 725 jp = makejob(cmd, 1); 726 mode = cmd->ncmd.backgnd; 727 if (flags & EV_BACKCMD) { 728 mode = FORK_NOJOB; 729 if (pipe(pip) < 0) 730 error("Pipe call failed"); 731 } 732 if (forkshell(jp, cmd, mode) != 0) 733 goto parent; /* at end of routine */ 734 if (flags & EV_BACKCMD) { 735 FORCEINTON; 736 close(pip[0]); 737 if (pip[1] != 1) { 738 close(1); 739 copyfd(pip[1], 1); 740 close(pip[1]); 741 } 742 } 743 flags |= EV_EXIT; 744 } 745 746 /* This is the child process if a fork occurred. */ 747 /* Execute the command. */ 748 if (cmdentry.cmdtype == CMDFUNCTION) { 749 #ifdef DEBUG 750 trputs("Shell function: "); trargs(argv); 751 #endif 752 redirect(cmd->ncmd.redirect, REDIR_PUSH); 753 saveparam = shellparam; 754 shellparam.malloc = 0; 755 shellparam.reset = 1; 756 shellparam.nparam = argc - 1; 757 shellparam.p = argv + 1; 758 shellparam.optnext = NULL; 759 INTOFF; 760 savelocalvars = localvars; 761 localvars = NULL; 762 INTON; 763 if (setjmp(jmploc.loc)) { 764 if (exception == EXSHELLPROC) 765 freeparam((struct shparam *)&saveparam); 766 else { 767 freeparam(&shellparam); 768 shellparam = saveparam; 769 } 770 poplocalvars(); 771 localvars = savelocalvars; 772 handler = savehandler; 773 longjmp(handler->loc, 1); 774 } 775 savehandler = handler; 776 handler = &jmploc; 777 for (sp = varlist.list ; sp ; sp = sp->next) 778 mklocal(sp->text); 779 funcnest++; 780 if (flags & EV_TESTED) 781 evaltree(cmdentry.u.func, EV_TESTED); 782 else 783 evaltree(cmdentry.u.func, 0); 784 funcnest--; 785 INTOFF; 786 poplocalvars(); 787 localvars = savelocalvars; 788 freeparam(&shellparam); 789 shellparam = saveparam; 790 handler = savehandler; 791 popredir(); 792 INTON; 793 if (evalskip == SKIPFUNC) { 794 evalskip = 0; 795 skipcount = 0; 796 } 797 if (flags & EV_EXIT) 798 exitshell(exitstatus); 799 } else if (cmdentry.cmdtype == CMDBUILTIN) { 800 #ifdef DEBUG 801 trputs("builtin command: "); trargs(argv); 802 #endif 803 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 804 if (flags == EV_BACKCMD) { 805 memout.nleft = 0; 806 memout.nextc = memout.buf; 807 memout.bufsize = 64; 808 mode |= REDIR_BACKQ; 809 } 810 redirect(cmd->ncmd.redirect, mode); 811 savecmdname = commandname; 812 cmdenviron = varlist.list; 813 e = -1; 814 if (setjmp(jmploc.loc)) { 815 e = exception; 816 exitstatus = (e == EXINT)? SIGINT+128 : 2; 817 goto cmddone; 818 } 819 savehandler = handler; 820 handler = &jmploc; 821 commandname = argv[0]; 822 argptr = argv + 1; 823 optptr = NULL; /* initialize nextopt */ 824 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 825 flushall(); 826 cmddone: 827 out1 = &output; 828 out2 = &errout; 829 freestdout(); 830 if (e != EXSHELLPROC) { 831 commandname = savecmdname; 832 if (flags & EV_EXIT) { 833 exitshell(exitstatus); 834 } 835 } 836 handler = savehandler; 837 if (e != -1) { 838 if ((e != EXERROR && e != EXEXEC) 839 || cmdentry.u.index == BLTINCMD 840 || cmdentry.u.index == DOTCMD 841 || cmdentry.u.index == EVALCMD 842 #ifndef NO_HISTORY 843 || cmdentry.u.index == HISTCMD 844 #endif 845 || cmdentry.u.index == EXECCMD) 846 exraise(e); 847 FORCEINTON; 848 } 849 if (cmdentry.u.index != EXECCMD) 850 popredir(); 851 if (flags == EV_BACKCMD) { 852 backcmd->buf = memout.buf; 853 backcmd->nleft = memout.nextc - memout.buf; 854 memout.buf = NULL; 855 } 856 } else { 857 #ifdef DEBUG 858 trputs("normal command: "); trargs(argv); 859 #endif 860 clearredir(); 861 redirect(cmd->ncmd.redirect, 0); 862 for (sp = varlist.list ; sp ; sp = sp->next) 863 setvareq(sp->text, VEXPORT|VSTACK); 864 envp = environment(); 865 shellexec(argv, envp, pathval(), cmdentry.u.index); 866 /*NOTREACHED*/ 867 } 868 goto out; 869 870 parent: /* parent process gets here (if we forked) */ 871 if (mode == 0) { /* argument to fork */ 872 INTOFF; 873 exitstatus = waitforjob(jp, &realstatus); 874 INTON; 875 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 876 evalskip = SKIPBREAK; 877 skipcount = loopnest; 878 } 879 } else if (mode == 2) { 880 backcmd->fd = pip[0]; 881 close(pip[1]); 882 backcmd->jp = jp; 883 } 884 885 out: 886 if (lastarg) 887 setvar("_", lastarg, 0); 888 popstackmark(&smark); 889 } 890 891 892 893 /* 894 * Search for a command. This is called before we fork so that the 895 * location of the command will be available in the parent as well as 896 * the child. The check for "goodname" is an overly conservative 897 * check that the name will not be subject to expansion. 898 */ 899 900 STATIC void 901 prehash(n) 902 union node *n; 903 { 904 struct cmdentry entry; 905 906 if (n->type == NCMD && n->ncmd.args) 907 if (goodname(n->ncmd.args->narg.text)) 908 find_command(n->ncmd.args->narg.text, &entry, 0, 909 pathval()); 910 } 911 912 913 914 /* 915 * Builtin commands. Builtin commands whose functions are closely 916 * tied to evaluation are implemented here. 917 */ 918 919 /* 920 * No command given, or a bltin command with no arguments. Set the 921 * specified variables. 922 */ 923 924 int 925 bltincmd(argc, argv) 926 int argc __unused; 927 char **argv __unused; 928 { 929 listsetvar(cmdenviron); 930 /* 931 * Preserve exitstatus of a previous possible redirection 932 * as POSIX mandates 933 */ 934 return exitstatus; 935 } 936 937 938 /* 939 * Handle break and continue commands. Break, continue, and return are 940 * all handled by setting the evalskip flag. The evaluation routines 941 * above all check this flag, and if it is set they start skipping 942 * commands rather than executing them. The variable skipcount is 943 * the number of loops to break/continue, or the number of function 944 * levels to return. (The latter is always 1.) It should probably 945 * be an error to break out of more loops than exist, but it isn't 946 * in the standard shell so we don't make it one here. 947 */ 948 949 int 950 breakcmd(argc, argv) 951 int argc; 952 char **argv; 953 { 954 int n = argc > 1 ? number(argv[1]) : 1; 955 956 if (n > loopnest) 957 n = loopnest; 958 if (n > 0) { 959 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 960 skipcount = n; 961 } 962 return 0; 963 } 964 965 966 /* 967 * The return command. 968 */ 969 970 int 971 returncmd(argc, argv) 972 int argc; 973 char **argv; 974 { 975 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 976 977 if (funcnest) { 978 evalskip = SKIPFUNC; 979 skipcount = 1; 980 } else { 981 /* skip the rest of the file */ 982 evalskip = SKIPFILE; 983 skipcount = 1; 984 } 985 return ret; 986 } 987 988 989 int 990 falsecmd(argc, argv) 991 int argc __unused; 992 char **argv __unused; 993 { 994 return 1; 995 } 996 997 998 int 999 truecmd(argc, argv) 1000 int argc __unused; 1001 char **argv __unused; 1002 { 1003 return 0; 1004 } 1005 1006 1007 int 1008 execcmd(argc, argv) 1009 int argc; 1010 char **argv; 1011 { 1012 if (argc > 1) { 1013 struct strlist *sp; 1014 1015 iflag = 0; /* exit on error */ 1016 mflag = 0; 1017 optschanged(); 1018 for (sp = cmdenviron; sp ; sp = sp->next) 1019 setvareq(sp->text, VEXPORT|VSTACK); 1020 shellexec(argv + 1, environment(), pathval(), 0); 1021 1022 } 1023 return 0; 1024 } 1025