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 if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 279 exitshell(exitstatus); 280 } 281 282 283 STATIC void 284 evalloop(n) 285 union node *n; 286 { 287 int status; 288 289 loopnest++; 290 status = 0; 291 for (;;) { 292 evaltree(n->nbinary.ch1, EV_TESTED); 293 if (evalskip) { 294 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 295 evalskip = 0; 296 continue; 297 } 298 if (evalskip == SKIPBREAK && --skipcount <= 0) 299 evalskip = 0; 300 break; 301 } 302 if (n->type == NWHILE) { 303 if (exitstatus != 0) 304 break; 305 } else { 306 if (exitstatus == 0) 307 break; 308 } 309 evaltree(n->nbinary.ch2, 0); 310 status = exitstatus; 311 if (evalskip) 312 goto skipping; 313 } 314 loopnest--; 315 exitstatus = status; 316 } 317 318 319 320 STATIC void 321 evalfor(n) 322 union node *n; 323 { 324 struct arglist arglist; 325 union node *argp; 326 struct strlist *sp; 327 struct stackmark smark; 328 329 setstackmark(&smark); 330 arglist.lastp = &arglist.list; 331 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 332 oexitstatus = exitstatus; 333 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 334 if (evalskip) 335 goto out; 336 } 337 *arglist.lastp = NULL; 338 339 exitstatus = 0; 340 loopnest++; 341 for (sp = arglist.list ; sp ; sp = sp->next) { 342 setvar(n->nfor.var, sp->text, 0); 343 evaltree(n->nfor.body, 0); 344 if (evalskip) { 345 if (evalskip == SKIPCONT && --skipcount <= 0) { 346 evalskip = 0; 347 continue; 348 } 349 if (evalskip == SKIPBREAK && --skipcount <= 0) 350 evalskip = 0; 351 break; 352 } 353 } 354 loopnest--; 355 out: 356 popstackmark(&smark); 357 } 358 359 360 361 STATIC void 362 evalcase(n, flags) 363 union node *n; 364 int flags; 365 { 366 union node *cp; 367 union node *patp; 368 struct arglist arglist; 369 struct stackmark smark; 370 371 setstackmark(&smark); 372 arglist.lastp = &arglist.list; 373 oexitstatus = exitstatus; 374 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 375 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 376 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 377 if (casematch(patp, arglist.list->text)) { 378 if (evalskip == 0) { 379 evaltree(cp->nclist.body, flags); 380 } 381 goto out; 382 } 383 } 384 } 385 out: 386 popstackmark(&smark); 387 } 388 389 390 391 /* 392 * Kick off a subshell to evaluate a tree. 393 */ 394 395 STATIC void 396 evalsubshell(n, flags) 397 union node *n; 398 int flags; 399 { 400 struct job *jp; 401 int backgnd = (n->type == NBACKGND); 402 403 expredir(n->nredir.redirect); 404 jp = makejob(n, 1); 405 if (forkshell(jp, n, backgnd) == 0) { 406 if (backgnd) 407 flags &=~ EV_TESTED; 408 redirect(n->nredir.redirect, 0); 409 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 410 } 411 if (! backgnd) { 412 INTOFF; 413 exitstatus = waitforjob(jp, (int *)NULL); 414 INTON; 415 } 416 } 417 418 419 420 /* 421 * Compute the names of the files in a redirection list. 422 */ 423 424 STATIC void 425 expredir(n) 426 union node *n; 427 { 428 union node *redir; 429 430 for (redir = n ; redir ; redir = redir->nfile.next) { 431 struct arglist fn; 432 fn.lastp = &fn.list; 433 oexitstatus = exitstatus; 434 switch (redir->type) { 435 case NFROM: 436 case NTO: 437 case NAPPEND: 438 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 439 redir->nfile.expfname = fn.list->text; 440 break; 441 case NFROMFD: 442 case NTOFD: 443 if (redir->ndup.vname) { 444 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 445 fixredir(redir, fn.list->text, 1); 446 } 447 break; 448 } 449 } 450 } 451 452 453 454 /* 455 * Evaluate a pipeline. All the processes in the pipeline are children 456 * of the process creating the pipeline. (This differs from some versions 457 * of the shell, which make the last process in a pipeline the parent 458 * of all the rest.) 459 */ 460 461 STATIC void 462 evalpipe(n) 463 union node *n; 464 { 465 struct job *jp; 466 struct nodelist *lp; 467 int pipelen; 468 int prevfd; 469 int pip[2]; 470 471 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 472 pipelen = 0; 473 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 474 pipelen++; 475 INTOFF; 476 jp = makejob(n, pipelen); 477 prevfd = -1; 478 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 479 prehash(lp->n); 480 pip[1] = -1; 481 if (lp->next) { 482 if (pipe(pip) < 0) { 483 close(prevfd); 484 error("Pipe call failed"); 485 } 486 } 487 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 488 INTON; 489 if (prevfd > 0) { 490 close(0); 491 copyfd(prevfd, 0); 492 close(prevfd); 493 } 494 if (pip[1] >= 0) { 495 close(pip[0]); 496 if (pip[1] != 1) { 497 close(1); 498 copyfd(pip[1], 1); 499 close(pip[1]); 500 } 501 } 502 evaltree(lp->n, EV_EXIT); 503 } 504 if (prevfd >= 0) 505 close(prevfd); 506 prevfd = pip[0]; 507 close(pip[1]); 508 } 509 INTON; 510 if (n->npipe.backgnd == 0) { 511 INTOFF; 512 exitstatus = waitforjob(jp, (int *)NULL); 513 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 514 INTON; 515 } 516 } 517 518 519 520 /* 521 * Execute a command inside back quotes. If it's a builtin command, we 522 * want to save its output in a block obtained from malloc. Otherwise 523 * we fork off a subprocess and get the output of the command via a pipe. 524 * Should be called with interrupts off. 525 */ 526 527 void 528 evalbackcmd(n, result) 529 union node *n; 530 struct backcmd *result; 531 { 532 int pip[2]; 533 struct job *jp; 534 struct stackmark smark; /* unnecessary */ 535 536 setstackmark(&smark); 537 result->fd = -1; 538 result->buf = NULL; 539 result->nleft = 0; 540 result->jp = NULL; 541 if (n == NULL) { 542 exitstatus = 0; 543 goto out; 544 } 545 if (n->type == NCMD) { 546 exitstatus = oexitstatus; 547 evalcommand(n, EV_BACKCMD, result); 548 } else { 549 exitstatus = 0; 550 if (pipe(pip) < 0) 551 error("Pipe call failed"); 552 jp = makejob(n, 1); 553 if (forkshell(jp, n, FORK_NOJOB) == 0) { 554 FORCEINTON; 555 close(pip[0]); 556 if (pip[1] != 1) { 557 close(1); 558 copyfd(pip[1], 1); 559 close(pip[1]); 560 } 561 evaltree(n, EV_EXIT); 562 } 563 close(pip[1]); 564 result->fd = pip[0]; 565 result->jp = jp; 566 } 567 out: 568 popstackmark(&smark); 569 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 570 result->fd, result->buf, result->nleft, result->jp)); 571 } 572 573 574 575 /* 576 * Execute a simple command. 577 */ 578 579 STATIC void 580 evalcommand(cmd, flags, backcmd) 581 union node *cmd; 582 int flags; 583 struct backcmd *backcmd; 584 { 585 struct stackmark smark; 586 union node *argp; 587 struct arglist arglist; 588 struct arglist varlist; 589 char **argv; 590 int argc; 591 char **envp; 592 int varflag; 593 struct strlist *sp; 594 int mode; 595 int pip[2]; 596 struct cmdentry cmdentry; 597 struct job *jp; 598 struct jmploc jmploc; 599 struct jmploc *volatile savehandler; 600 char *volatile savecmdname; 601 volatile struct shparam saveparam; 602 struct localvar *volatile savelocalvars; 603 volatile int e; 604 char *lastarg; 605 int realstatus; 606 #if __GNUC__ 607 /* Avoid longjmp clobbering */ 608 (void) &argv; 609 (void) &argc; 610 (void) &lastarg; 611 (void) &flags; 612 #endif 613 614 /* First expand the arguments. */ 615 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 616 setstackmark(&smark); 617 arglist.lastp = &arglist.list; 618 varlist.lastp = &varlist.list; 619 varflag = 1; 620 oexitstatus = exitstatus; 621 exitstatus = 0; 622 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 623 char *p = argp->narg.text; 624 if (varflag && is_name(*p)) { 625 do { 626 p++; 627 } while (is_in_name(*p)); 628 if (*p == '=') { 629 expandarg(argp, &varlist, EXP_VARTILDE); 630 continue; 631 } 632 } 633 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 634 varflag = 0; 635 } 636 *arglist.lastp = NULL; 637 *varlist.lastp = NULL; 638 expredir(cmd->ncmd.redirect); 639 argc = 0; 640 for (sp = arglist.list ; sp ; sp = sp->next) 641 argc++; 642 argv = stalloc(sizeof (char *) * (argc + 1)); 643 644 for (sp = arglist.list ; sp ; sp = sp->next) { 645 TRACE(("evalcommand arg: %s\n", sp->text)); 646 *argv++ = sp->text; 647 } 648 *argv = NULL; 649 lastarg = NULL; 650 if (iflag && funcnest == 0 && argc > 0) 651 lastarg = argv[-1]; 652 argv -= argc; 653 654 /* Print the command if xflag is set. */ 655 if (xflag) { 656 outc('+', &errout); 657 for (sp = varlist.list ; sp ; sp = sp->next) { 658 outc(' ', &errout); 659 out2str(sp->text); 660 } 661 for (sp = arglist.list ; sp ; sp = sp->next) { 662 outc(' ', &errout); 663 out2str(sp->text); 664 } 665 outc('\n', &errout); 666 flushout(&errout); 667 } 668 669 /* Now locate the command. */ 670 if (argc == 0) { 671 cmdentry.cmdtype = CMDBUILTIN; 672 cmdentry.u.index = BLTINCMD; 673 } else { 674 static const char PATH[] = "PATH="; 675 char *path = pathval(); 676 677 /* 678 * Modify the command lookup path, if a PATH= assignment 679 * is present 680 */ 681 for (sp = varlist.list ; sp ; sp = sp->next) 682 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 683 path = sp->text + sizeof(PATH) - 1; 684 685 find_command(argv[0], &cmdentry, 1, path); 686 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 687 exitstatus = 127; 688 flushout(&errout); 689 return; 690 } 691 /* implement the bltin builtin here */ 692 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 693 for (;;) { 694 argv++; 695 if (--argc == 0) 696 break; 697 if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 698 outfmt(&errout, "%s: not found\n", *argv); 699 exitstatus = 127; 700 flushout(&errout); 701 return; 702 } 703 if (cmdentry.u.index != BLTINCMD) 704 break; 705 } 706 } 707 } 708 709 /* Fork off a child process if necessary. */ 710 if (cmd->ncmd.backgnd 711 || (cmdentry.cmdtype == CMDNORMAL 712 && ((flags & EV_EXIT) == 0 || Tflag)) 713 || ((flags & EV_BACKCMD) != 0 714 && (cmdentry.cmdtype != CMDBUILTIN 715 || cmdentry.u.index == CDCMD 716 || cmdentry.u.index == DOTCMD 717 || cmdentry.u.index == EVALCMD))) { 718 jp = makejob(cmd, 1); 719 mode = cmd->ncmd.backgnd; 720 if (flags & EV_BACKCMD) { 721 mode = FORK_NOJOB; 722 if (pipe(pip) < 0) 723 error("Pipe call failed"); 724 } 725 if (forkshell(jp, cmd, mode) != 0) 726 goto parent; /* at end of routine */ 727 if (flags & EV_BACKCMD) { 728 FORCEINTON; 729 close(pip[0]); 730 if (pip[1] != 1) { 731 close(1); 732 copyfd(pip[1], 1); 733 close(pip[1]); 734 } 735 } 736 flags |= EV_EXIT; 737 } 738 739 /* This is the child process if a fork occurred. */ 740 /* Execute the command. */ 741 if (cmdentry.cmdtype == CMDFUNCTION) { 742 #ifdef DEBUG 743 trputs("Shell function: "); trargs(argv); 744 #endif 745 redirect(cmd->ncmd.redirect, REDIR_PUSH); 746 saveparam = shellparam; 747 shellparam.malloc = 0; 748 shellparam.reset = 1; 749 shellparam.nparam = argc - 1; 750 shellparam.p = argv + 1; 751 shellparam.optnext = NULL; 752 INTOFF; 753 savelocalvars = localvars; 754 localvars = NULL; 755 INTON; 756 if (setjmp(jmploc.loc)) { 757 if (exception == EXSHELLPROC) 758 freeparam((struct shparam *)&saveparam); 759 else { 760 freeparam(&shellparam); 761 shellparam = saveparam; 762 } 763 poplocalvars(); 764 localvars = savelocalvars; 765 handler = savehandler; 766 longjmp(handler->loc, 1); 767 } 768 savehandler = handler; 769 handler = &jmploc; 770 for (sp = varlist.list ; sp ; sp = sp->next) 771 mklocal(sp->text); 772 funcnest++; 773 if (flags & EV_TESTED) 774 evaltree(cmdentry.u.func, EV_TESTED); 775 else 776 evaltree(cmdentry.u.func, 0); 777 funcnest--; 778 INTOFF; 779 poplocalvars(); 780 localvars = savelocalvars; 781 freeparam(&shellparam); 782 shellparam = saveparam; 783 handler = savehandler; 784 popredir(); 785 INTON; 786 if (evalskip == SKIPFUNC) { 787 evalskip = 0; 788 skipcount = 0; 789 } 790 if (flags & EV_EXIT) 791 exitshell(exitstatus); 792 } else if (cmdentry.cmdtype == CMDBUILTIN) { 793 #ifdef DEBUG 794 trputs("builtin command: "); trargs(argv); 795 #endif 796 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 797 if (flags == EV_BACKCMD) { 798 memout.nleft = 0; 799 memout.nextc = memout.buf; 800 memout.bufsize = 64; 801 mode |= REDIR_BACKQ; 802 } 803 redirect(cmd->ncmd.redirect, mode); 804 savecmdname = commandname; 805 cmdenviron = varlist.list; 806 e = -1; 807 if (setjmp(jmploc.loc)) { 808 e = exception; 809 exitstatus = (e == EXINT)? SIGINT+128 : 2; 810 goto cmddone; 811 } 812 savehandler = handler; 813 handler = &jmploc; 814 commandname = argv[0]; 815 argptr = argv + 1; 816 optptr = NULL; /* initialize nextopt */ 817 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 818 flushall(); 819 cmddone: 820 out1 = &output; 821 out2 = &errout; 822 freestdout(); 823 if (e != EXSHELLPROC) { 824 commandname = savecmdname; 825 if (flags & EV_EXIT) { 826 exitshell(exitstatus); 827 } 828 } 829 handler = savehandler; 830 if (e != -1) { 831 if ((e != EXERROR && e != EXEXEC) 832 || cmdentry.u.index == BLTINCMD 833 || cmdentry.u.index == DOTCMD 834 || cmdentry.u.index == EVALCMD 835 #ifndef NO_HISTORY 836 || cmdentry.u.index == HISTCMD 837 #endif 838 || cmdentry.u.index == EXECCMD) 839 exraise(e); 840 FORCEINTON; 841 } 842 if (cmdentry.u.index != EXECCMD) 843 popredir(); 844 if (flags == EV_BACKCMD) { 845 backcmd->buf = memout.buf; 846 backcmd->nleft = memout.nextc - memout.buf; 847 memout.buf = NULL; 848 } 849 } else { 850 #ifdef DEBUG 851 trputs("normal command: "); trargs(argv); 852 #endif 853 clearredir(); 854 redirect(cmd->ncmd.redirect, 0); 855 for (sp = varlist.list ; sp ; sp = sp->next) 856 setvareq(sp->text, VEXPORT|VSTACK); 857 envp = environment(); 858 shellexec(argv, envp, pathval(), cmdentry.u.index); 859 /*NOTREACHED*/ 860 } 861 goto out; 862 863 parent: /* parent process gets here (if we forked) */ 864 if (mode == 0) { /* argument to fork */ 865 INTOFF; 866 exitstatus = waitforjob(jp, &realstatus); 867 INTON; 868 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 869 evalskip = SKIPBREAK; 870 skipcount = loopnest; 871 } 872 } else if (mode == 2) { 873 backcmd->fd = pip[0]; 874 close(pip[1]); 875 backcmd->jp = jp; 876 } 877 878 out: 879 if (lastarg) 880 setvar("_", lastarg, 0); 881 popstackmark(&smark); 882 } 883 884 885 886 /* 887 * Search for a command. This is called before we fork so that the 888 * location of the command will be available in the parent as well as 889 * the child. The check for "goodname" is an overly conservative 890 * check that the name will not be subject to expansion. 891 */ 892 893 STATIC void 894 prehash(n) 895 union node *n; 896 { 897 struct cmdentry entry; 898 899 if (n->type == NCMD && n->ncmd.args) 900 if (goodname(n->ncmd.args->narg.text)) 901 find_command(n->ncmd.args->narg.text, &entry, 0, 902 pathval()); 903 } 904 905 906 907 /* 908 * Builtin commands. Builtin commands whose functions are closely 909 * tied to evaluation are implemented here. 910 */ 911 912 /* 913 * No command given, or a bltin command with no arguments. Set the 914 * specified variables. 915 */ 916 917 int 918 bltincmd(argc, argv) 919 int argc __unused; 920 char **argv __unused; 921 { 922 listsetvar(cmdenviron); 923 /* 924 * Preserve exitstatus of a previous possible redirection 925 * as POSIX mandates 926 */ 927 return exitstatus; 928 } 929 930 931 /* 932 * Handle break and continue commands. Break, continue, and return are 933 * all handled by setting the evalskip flag. The evaluation routines 934 * above all check this flag, and if it is set they start skipping 935 * commands rather than executing them. The variable skipcount is 936 * the number of loops to break/continue, or the number of function 937 * levels to return. (The latter is always 1.) It should probably 938 * be an error to break out of more loops than exist, but it isn't 939 * in the standard shell so we don't make it one here. 940 */ 941 942 int 943 breakcmd(argc, argv) 944 int argc; 945 char **argv; 946 { 947 int n = argc > 1 ? number(argv[1]) : 1; 948 949 if (n > loopnest) 950 n = loopnest; 951 if (n > 0) { 952 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 953 skipcount = n; 954 } 955 return 0; 956 } 957 958 959 /* 960 * The return command. 961 */ 962 963 int 964 returncmd(argc, argv) 965 int argc; 966 char **argv; 967 { 968 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 969 970 if (funcnest) { 971 evalskip = SKIPFUNC; 972 skipcount = 1; 973 } else { 974 /* skip the rest of the file */ 975 evalskip = SKIPFILE; 976 skipcount = 1; 977 } 978 return ret; 979 } 980 981 982 int 983 falsecmd(argc, argv) 984 int argc __unused; 985 char **argv __unused; 986 { 987 return 1; 988 } 989 990 991 int 992 truecmd(argc, argv) 993 int argc __unused; 994 char **argv __unused; 995 { 996 return 0; 997 } 998 999 1000 int 1001 execcmd(argc, argv) 1002 int argc; 1003 char **argv; 1004 { 1005 if (argc > 1) { 1006 struct strlist *sp; 1007 1008 iflag = 0; /* exit on error */ 1009 mflag = 0; 1010 optschanged(); 1011 for (sp = cmdenviron; sp ; sp = sp->next) 1012 setvareq(sp->text, VEXPORT|VSTACK); 1013 shellexec(argv + 1, environment(), pathval(), 0); 1014 1015 } 1016 return 0; 1017 } 1018