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