1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * 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 static char sccsid[] = "@(#)eval.c 5.4 (Berkeley) 4/16/92"; 39 #endif /* not lint */ 40 41 /* 42 * Evaluate a command. 43 */ 44 45 #include "shell.h" 46 #include "nodes.h" 47 #include "syntax.h" 48 #include "expand.h" 49 #include "parser.h" 50 #include "jobs.h" 51 #include "eval.h" 52 #include "builtins.h" 53 #include "options.h" 54 #include "exec.h" 55 #include "redir.h" 56 #include "input.h" 57 #include "output.h" 58 #include "trap.h" 59 #include "var.h" 60 #include "memalloc.h" 61 #include "error.h" 62 #include "mystring.h" 63 #include <signal.h> 64 65 66 /* flags in argument to evaltree */ 67 #define EV_EXIT 01 /* exit after evaluating tree */ 68 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 69 #define EV_BACKCMD 04 /* command executing within back quotes */ 70 71 72 /* reasons for skipping commands (see comment on breakcmd routine) */ 73 #define SKIPBREAK 1 74 #define SKIPCONT 2 75 #define SKIPFUNC 3 76 77 MKINIT int evalskip; /* set if we are skipping commands */ 78 STATIC int skipcount; /* number of levels to skip */ 79 MKINIT int loopnest; /* current loop nesting level */ 80 int funcnest; /* depth of function calls */ 81 82 83 char *commandname; 84 struct strlist *cmdenviron; 85 int exitstatus; /* exit status of last command */ 86 87 88 #ifdef __STDC__ 89 STATIC void evalloop(union node *); 90 STATIC void evalfor(union node *); 91 STATIC void evalcase(union node *, int); 92 STATIC void evalsubshell(union node *, int); 93 STATIC void expredir(union node *); 94 STATIC void evalpipe(union node *); 95 STATIC void evalcommand(union node *, int, struct backcmd *); 96 STATIC void prehash(union node *); 97 #else 98 STATIC void evalloop(); 99 STATIC void evalfor(); 100 STATIC void evalcase(); 101 STATIC void evalsubshell(); 102 STATIC void expredir(); 103 STATIC void evalpipe(); 104 STATIC void evalcommand(); 105 STATIC void prehash(); 106 #endif 107 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 evalcmd(argc, argv) 135 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); 157 } 158 return exitstatus; 159 } 160 161 162 /* 163 * Execute a command or commands contained in a string. 164 */ 165 166 void 167 evalstring(s) 168 char *s; 169 { 170 union node *n; 171 struct stackmark smark; 172 173 setstackmark(&smark); 174 setinputstring(s, 1); 175 while ((n = parsecmd(0)) != NEOF) { 176 evaltree(n, 0); 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(n, flags) 192 union node *n; 193 { 194 if (n == NULL) { 195 TRACE(("evaltree(NULL) called\n")); 196 return; 197 } 198 TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type)); 199 switch (n->type) { 200 case NSEMI: 201 evaltree(n->nbinary.ch1, 0); 202 if (evalskip) 203 goto out; 204 evaltree(n->nbinary.ch2, flags); 205 break; 206 case NAND: 207 evaltree(n->nbinary.ch1, EV_TESTED); 208 if (evalskip || exitstatus != 0) 209 goto out; 210 evaltree(n->nbinary.ch2, flags); 211 break; 212 case NOR: 213 evaltree(n->nbinary.ch1, EV_TESTED); 214 if (evalskip || exitstatus == 0) 215 goto out; 216 evaltree(n->nbinary.ch2, flags); 217 break; 218 case NREDIR: 219 expredir(n->nredir.redirect); 220 redirect(n->nredir.redirect, REDIR_PUSH); 221 evaltree(n->nredir.n, flags); 222 popredir(); 223 break; 224 case NSUBSHELL: 225 evalsubshell(n, flags); 226 break; 227 case NBACKGND: 228 evalsubshell(n, flags); 229 break; 230 case NIF: { 231 int status = 0; 232 233 evaltree(n->nif.test, EV_TESTED); 234 if (evalskip) 235 goto out; 236 if (exitstatus == 0) { 237 evaltree(n->nif.ifpart, flags); 238 status = exitstatus; 239 } else if (n->nif.elsepart) { 240 evaltree(n->nif.elsepart, flags); 241 status = exitstatus; 242 } 243 exitstatus = status; 244 break; 245 } 246 case NWHILE: 247 case NUNTIL: 248 evalloop(n); 249 break; 250 case NFOR: 251 evalfor(n); 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 265 case NPIPE: 266 evalpipe(n); 267 break; 268 case NCMD: 269 evalcommand(n, flags, (struct backcmd *)NULL); 270 break; 271 default: 272 out1fmt("Node type = %d\n", n->type); 273 flushout(&output); 274 break; 275 } 276 out: 277 if (pendingsigs) 278 dotrap(); 279 if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 280 exitshell(exitstatus); 281 } 282 283 284 STATIC void 285 evalloop(n) 286 union node *n; 287 { 288 int status; 289 290 loopnest++; 291 status = 0; 292 for (;;) { 293 evaltree(n->nbinary.ch1, EV_TESTED); 294 if (evalskip) { 295 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 296 evalskip = 0; 297 continue; 298 } 299 if (evalskip == SKIPBREAK && --skipcount <= 0) 300 evalskip = 0; 301 break; 302 } 303 if (n->type == NWHILE) { 304 if (exitstatus != 0) 305 break; 306 } else { 307 if (exitstatus == 0) 308 break; 309 } 310 evaltree(n->nbinary.ch2, 0); 311 status = exitstatus; 312 if (evalskip) 313 goto skipping; 314 } 315 loopnest--; 316 exitstatus = status; 317 } 318 319 320 321 STATIC void 322 evalfor(n) 323 union node *n; 324 { 325 struct arglist arglist; 326 union node *argp; 327 struct strlist *sp; 328 struct stackmark smark; 329 330 setstackmark(&smark); 331 arglist.lastp = &arglist.list; 332 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 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 { 365 union node *cp; 366 union node *patp; 367 struct arglist arglist; 368 struct stackmark smark; 369 370 setstackmark(&smark); 371 arglist.lastp = &arglist.list; 372 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 373 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 374 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 375 if (casematch(patp, arglist.list->text)) { 376 if (evalskip == 0) { 377 evaltree(cp->nclist.body, flags); 378 } 379 goto out; 380 } 381 } 382 } 383 out: 384 popstackmark(&smark); 385 } 386 387 388 389 /* 390 * Kick off a subshell to evaluate a tree. 391 */ 392 393 STATIC void 394 evalsubshell(n, flags) 395 union node *n; 396 { 397 struct job *jp; 398 int backgnd = (n->type == NBACKGND); 399 400 expredir(n->nredir.redirect); 401 jp = makejob(n, 1); 402 if (forkshell(jp, n, backgnd) == 0) { 403 if (backgnd) 404 flags &=~ EV_TESTED; 405 redirect(n->nredir.redirect, 0); 406 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 407 } 408 if (! backgnd) { 409 INTOFF; 410 exitstatus = waitforjob(jp); 411 INTON; 412 } 413 } 414 415 416 417 /* 418 * Compute the names of the files in a redirection list. 419 */ 420 421 STATIC void 422 expredir(n) 423 union node *n; 424 { 425 register union node *redir; 426 427 for (redir = n ; redir ; redir = redir->nfile.next) { 428 if (redir->type == NFROM 429 || redir->type == NTO 430 || redir->type == NAPPEND) { 431 struct arglist fn; 432 fn.lastp = &fn.list; 433 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 434 redir->nfile.expfname = fn.list->text; 435 } 436 } 437 } 438 439 440 441 /* 442 * Evaluate a pipeline. All the processes in the pipeline are children 443 * of the process creating the pipeline. (This differs from some versions 444 * of the shell, which make the last process in a pipeline the parent 445 * of all the rest.) 446 */ 447 448 STATIC void 449 evalpipe(n) 450 union node *n; 451 { 452 struct job *jp; 453 struct nodelist *lp; 454 int pipelen; 455 int prevfd; 456 int pip[2]; 457 458 TRACE(("evalpipe(0x%x) called\n", (int)n)); 459 pipelen = 0; 460 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 461 pipelen++; 462 INTOFF; 463 jp = makejob(n, pipelen); 464 prevfd = -1; 465 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 466 prehash(lp->n); 467 pip[1] = -1; 468 if (lp->next) { 469 if (pipe(pip) < 0) { 470 close(prevfd); 471 error("Pipe call failed"); 472 } 473 } 474 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 475 INTON; 476 if (prevfd > 0) { 477 close(0); 478 copyfd(prevfd, 0); 479 close(prevfd); 480 } 481 if (pip[1] >= 0) { 482 close(pip[0]); 483 if (pip[1] != 1) { 484 close(1); 485 copyfd(pip[1], 1); 486 close(pip[1]); 487 } 488 } 489 evaltree(lp->n, EV_EXIT); 490 } 491 if (prevfd >= 0) 492 close(prevfd); 493 prevfd = pip[0]; 494 close(pip[1]); 495 } 496 INTON; 497 if (n->npipe.backgnd == 0) { 498 INTOFF; 499 exitstatus = waitforjob(jp); 500 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 501 INTON; 502 } 503 } 504 505 506 507 /* 508 * Execute a command inside back quotes. If it's a builtin command, we 509 * want to save its output in a block obtained from malloc. Otherwise 510 * we fork off a subprocess and get the output of the command via a pipe. 511 * Should be called with interrupts off. 512 */ 513 514 void 515 evalbackcmd(n, result) 516 union node *n; 517 struct backcmd *result; 518 { 519 int pip[2]; 520 struct job *jp; 521 struct stackmark smark; /* unnecessary */ 522 523 setstackmark(&smark); 524 result->fd = -1; 525 result->buf = NULL; 526 result->nleft = 0; 527 result->jp = NULL; 528 if (n->type == NCMD) { 529 evalcommand(n, EV_BACKCMD, result); 530 } else { 531 if (pipe(pip) < 0) 532 error("Pipe call failed"); 533 jp = makejob(n, 1); 534 if (forkshell(jp, n, FORK_NOJOB) == 0) { 535 FORCEINTON; 536 close(pip[0]); 537 if (pip[1] != 1) { 538 close(1); 539 copyfd(pip[1], 1); 540 close(pip[1]); 541 } 542 evaltree(n, EV_EXIT); 543 } 544 close(pip[1]); 545 result->fd = pip[0]; 546 result->jp = jp; 547 } 548 popstackmark(&smark); 549 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 550 result->fd, result->buf, result->nleft, result->jp)); 551 } 552 553 554 555 /* 556 * Execute a simple command. 557 */ 558 559 STATIC void 560 evalcommand(cmd, flags, backcmd) 561 union node *cmd; 562 struct backcmd *backcmd; 563 { 564 struct stackmark smark; 565 union node *argp; 566 struct arglist arglist; 567 struct arglist varlist; 568 char **argv; 569 int argc; 570 char **envp; 571 int varflag; 572 struct strlist *sp; 573 register char *p; 574 int mode; 575 int pip[2]; 576 struct cmdentry cmdentry; 577 struct job *jp; 578 struct jmploc jmploc; 579 struct jmploc *volatile savehandler; 580 char *volatile savecmdname; 581 volatile struct shparam saveparam; 582 struct localvar *volatile savelocalvars; 583 volatile int e; 584 char *lastarg; 585 586 /* First expand the arguments. */ 587 TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags)); 588 setstackmark(&smark); 589 arglist.lastp = &arglist.list; 590 varlist.lastp = &varlist.list; 591 varflag = 1; 592 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 593 p = argp->narg.text; 594 if (varflag && is_name(*p)) { 595 do { 596 p++; 597 } while (is_in_name(*p)); 598 if (*p == '=') { 599 expandarg(argp, &varlist, EXP_VARTILDE); 600 continue; 601 } 602 } 603 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 604 varflag = 0; 605 } 606 *arglist.lastp = NULL; 607 *varlist.lastp = NULL; 608 expredir(cmd->ncmd.redirect); 609 argc = 0; 610 for (sp = arglist.list ; sp ; sp = sp->next) 611 argc++; 612 argv = stalloc(sizeof (char *) * (argc + 1)); 613 for (sp = arglist.list ; sp ; sp = sp->next) { 614 TRACE(("evalcommand arg: %s\n", sp->text)); 615 *argv++ = sp->text; 616 } 617 *argv = NULL; 618 lastarg = NULL; 619 if (iflag && funcnest == 0 && argc > 0) 620 lastarg = argv[-1]; 621 argv -= argc; 622 623 /* Print the command if xflag is set. */ 624 if (xflag) { 625 outc('+', &errout); 626 for (sp = varlist.list ; sp ; sp = sp->next) { 627 outc(' ', &errout); 628 out2str(sp->text); 629 } 630 for (sp = arglist.list ; sp ; sp = sp->next) { 631 outc(' ', &errout); 632 out2str(sp->text); 633 } 634 outc('\n', &errout); 635 flushout(&errout); 636 } 637 638 /* Now locate the command. */ 639 if (argc == 0) { 640 cmdentry.cmdtype = CMDBUILTIN; 641 cmdentry.u.index = BLTINCMD; 642 } else { 643 find_command(argv[0], &cmdentry, 1); 644 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 645 exitstatus = 2; 646 flushout(&errout); 647 return; 648 } 649 /* implement the bltin builtin here */ 650 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 651 for (;;) { 652 argv++; 653 if (--argc == 0) 654 break; 655 if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 656 outfmt(&errout, "%s: not found\n", *argv); 657 exitstatus = 2; 658 flushout(&errout); 659 return; 660 } 661 if (cmdentry.u.index != BLTINCMD) 662 break; 663 } 664 } 665 } 666 667 /* Fork off a child process if necessary. */ 668 if (cmd->ncmd.backgnd 669 || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0 670 || (flags & EV_BACKCMD) != 0 671 && (cmdentry.cmdtype != CMDBUILTIN 672 || cmdentry.u.index == DOTCMD 673 || cmdentry.u.index == EVALCMD)) { 674 jp = makejob(cmd, 1); 675 mode = cmd->ncmd.backgnd; 676 if (flags & EV_BACKCMD) { 677 mode = FORK_NOJOB; 678 if (pipe(pip) < 0) 679 error("Pipe call failed"); 680 } 681 if (forkshell(jp, cmd, mode) != 0) 682 goto parent; /* at end of routine */ 683 if (flags & EV_BACKCMD) { 684 FORCEINTON; 685 close(pip[0]); 686 if (pip[1] != 1) { 687 close(1); 688 copyfd(pip[1], 1); 689 close(pip[1]); 690 } 691 } 692 flags |= EV_EXIT; 693 } 694 695 /* This is the child process if a fork occurred. */ 696 /* Execute the command. */ 697 if (cmdentry.cmdtype == CMDFUNCTION) { 698 trputs("Shell function: "); trargs(argv); 699 redirect(cmd->ncmd.redirect, REDIR_PUSH); 700 saveparam = shellparam; 701 shellparam.malloc = 0; 702 shellparam.nparam = argc - 1; 703 shellparam.p = argv + 1; 704 shellparam.optnext = NULL; 705 INTOFF; 706 savelocalvars = localvars; 707 localvars = NULL; 708 INTON; 709 if (setjmp(jmploc.loc)) { 710 if (exception == EXSHELLPROC) 711 freeparam((struct shparam *)&saveparam); 712 else { 713 freeparam(&shellparam); 714 shellparam = saveparam; 715 } 716 poplocalvars(); 717 localvars = savelocalvars; 718 handler = savehandler; 719 longjmp(handler->loc, 1); 720 } 721 savehandler = handler; 722 handler = &jmploc; 723 for (sp = varlist.list ; sp ; sp = sp->next) 724 mklocal(sp->text); 725 funcnest++; 726 evaltree(cmdentry.u.func, 0); 727 funcnest--; 728 INTOFF; 729 poplocalvars(); 730 localvars = savelocalvars; 731 freeparam(&shellparam); 732 shellparam = saveparam; 733 handler = savehandler; 734 popredir(); 735 INTON; 736 if (evalskip == SKIPFUNC) { 737 evalskip = 0; 738 skipcount = 0; 739 } 740 if (flags & EV_EXIT) 741 exitshell(exitstatus); 742 } else if (cmdentry.cmdtype == CMDBUILTIN) { 743 trputs("builtin command: "); trargs(argv); 744 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 745 if (flags == EV_BACKCMD) { 746 memout.nleft = 0; 747 memout.nextc = memout.buf; 748 memout.bufsize = 64; 749 mode |= REDIR_BACKQ; 750 } 751 redirect(cmd->ncmd.redirect, mode); 752 savecmdname = commandname; 753 cmdenviron = varlist.list; 754 e = -1; 755 if (setjmp(jmploc.loc)) { 756 e = exception; 757 exitstatus = (e == EXINT)? SIGINT+128 : 2; 758 goto cmddone; 759 } 760 savehandler = handler; 761 handler = &jmploc; 762 commandname = argv[0]; 763 argptr = argv + 1; 764 optptr = NULL; /* initialize nextopt */ 765 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 766 flushall(); 767 cmddone: 768 out1 = &output; 769 out2 = &errout; 770 freestdout(); 771 if (e != EXSHELLPROC) { 772 commandname = savecmdname; 773 if (flags & EV_EXIT) { 774 exitshell(exitstatus); 775 } 776 } 777 handler = savehandler; 778 if (e != -1) { 779 if (e != EXERROR || cmdentry.u.index == BLTINCMD 780 || cmdentry.u.index == DOTCMD 781 || cmdentry.u.index == EVALCMD 782 || cmdentry.u.index == EXECCMD) 783 exraise(e); 784 FORCEINTON; 785 } 786 if (cmdentry.u.index != EXECCMD) 787 popredir(); 788 if (flags == EV_BACKCMD) { 789 backcmd->buf = memout.buf; 790 backcmd->nleft = memout.nextc - memout.buf; 791 memout.buf = NULL; 792 } 793 } else { 794 trputs("normal command: "); trargs(argv); 795 clearredir(); 796 redirect(cmd->ncmd.redirect, 0); 797 if (varlist.list) { 798 p = stalloc(strlen(pathval()) + 1); 799 scopy(pathval(), p); 800 } else { 801 p = pathval(); 802 } 803 for (sp = varlist.list ; sp ; sp = sp->next) 804 setvareq(sp->text, VEXPORT|VSTACK); 805 envp = environment(); 806 shellexec(argv, envp, p, cmdentry.u.index); 807 /*NOTREACHED*/ 808 } 809 goto out; 810 811 parent: /* parent process gets here (if we forked) */ 812 if (mode == 0) { /* argument to fork */ 813 INTOFF; 814 exitstatus = waitforjob(jp); 815 INTON; 816 } else if (mode == 2) { 817 backcmd->fd = pip[0]; 818 close(pip[1]); 819 backcmd->jp = jp; 820 } 821 822 out: 823 if (lastarg) 824 setvar("_", lastarg, 0); 825 popstackmark(&smark); 826 } 827 828 829 830 /* 831 * Search for a command. This is called before we fork so that the 832 * location of the command will be available in the parent as well as 833 * the child. The check for "goodname" is an overly conservative 834 * check that the name will not be subject to expansion. 835 */ 836 837 STATIC void 838 prehash(n) 839 union node *n; 840 { 841 struct cmdentry entry; 842 843 if (n->type == NCMD && goodname(n->ncmd.args->narg.text)) 844 find_command(n->ncmd.args->narg.text, &entry, 0); 845 } 846 847 848 849 /* 850 * Builtin commands. Builtin commands whose functions are closely 851 * tied to evaluation are implemented here. 852 */ 853 854 /* 855 * No command given, or a bltin command with no arguments. Set the 856 * specified variables. 857 */ 858 859 bltincmd(argc, argv) char **argv; { 860 listsetvar(cmdenviron); 861 return exitstatus; 862 } 863 864 865 /* 866 * Handle break and continue commands. Break, continue, and return are 867 * all handled by setting the evalskip flag. The evaluation routines 868 * above all check this flag, and if it is set they start skipping 869 * commands rather than executing them. The variable skipcount is 870 * the number of loops to break/continue, or the number of function 871 * levels to return. (The latter is always 1.) It should probably 872 * be an error to break out of more loops than exist, but it isn't 873 * in the standard shell so we don't make it one here. 874 */ 875 876 breakcmd(argc, argv) char **argv; { 877 int n; 878 879 n = 1; 880 if (argc > 1) 881 n = number(argv[1]); 882 if (n > loopnest) 883 n = loopnest; 884 if (n > 0) { 885 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 886 skipcount = n; 887 } 888 return 0; 889 } 890 891 892 /* 893 * The return command. 894 */ 895 896 returncmd(argc, argv) char **argv; { 897 int ret; 898 899 ret = exitstatus; 900 if (argc > 1) 901 ret = number(argv[1]); 902 if (funcnest) { 903 evalskip = SKIPFUNC; 904 skipcount = 1; 905 } 906 return ret; 907 } 908 909 910 truecmd(argc, argv) char **argv; { 911 return 0; 912 } 913 914 915 execcmd(argc, argv) char **argv; { 916 if (argc > 1) { 917 iflag = 0; /* exit on error */ 918 setinteractive(0); 919 histedit(); 920 #if JOBS 921 jflag = 0; 922 setjobctl(0); 923 #endif 924 shellexec(argv + 1, environment(), pathval(), 0); 925 926 } 927 return 0; 928 } 929