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.3 (Berkeley) 4/12/91"; 39 static char rcsid[] = "$Header: /cvsroot/src/bin/sh/eval.c,v 1.4 1993/07/07 01:11:57 jtc 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 if (n->type == NCMD) { 525 evalcommand(n, EV_BACKCMD, result); 526 } else { 527 if (pipe(pip) < 0) 528 error("Pipe call failed"); 529 jp = makejob(n, 1); 530 if (forkshell(jp, n, FORK_NOJOB) == 0) { 531 FORCEINTON; 532 close(pip[0]); 533 if (pip[1] != 1) { 534 close(1); 535 copyfd(pip[1], 1); 536 close(pip[1]); 537 } 538 evaltree(n, EV_EXIT); 539 } 540 close(pip[1]); 541 result->fd = pip[0]; 542 result->jp = jp; 543 } 544 popstackmark(&smark); 545 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 546 result->fd, result->buf, result->nleft, result->jp)); 547 } 548 549 550 551 /* 552 * Execute a simple command. 553 */ 554 555 STATIC void 556 evalcommand(cmd, flags, backcmd) 557 union node *cmd; 558 struct backcmd *backcmd; 559 { 560 struct stackmark smark; 561 union node *argp; 562 struct arglist arglist; 563 struct arglist varlist; 564 char **argv; 565 int argc; 566 char **envp; 567 int varflag; 568 struct strlist *sp; 569 register char *p; 570 int mode; 571 int pip[2]; 572 struct cmdentry cmdentry; 573 struct job *jp; 574 struct jmploc jmploc; 575 struct jmploc *volatile savehandler; 576 char *volatile savecmdname; 577 volatile struct shparam saveparam; 578 struct localvar *volatile savelocalvars; 579 volatile int e; 580 char *lastarg; 581 582 /* First expand the arguments. */ 583 TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags)); 584 setstackmark(&smark); 585 arglist.lastp = &arglist.list; 586 varlist.lastp = &varlist.list; 587 varflag = 1; 588 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 589 p = argp->narg.text; 590 if (varflag && is_name(*p)) { 591 do { 592 p++; 593 } while (is_in_name(*p)); 594 if (*p == '=') { 595 expandarg(argp, &varlist, 0); 596 continue; 597 } 598 } 599 expandarg(argp, &arglist, 1); 600 varflag = 0; 601 } 602 *arglist.lastp = NULL; 603 *varlist.lastp = NULL; 604 expredir(cmd->ncmd.redirect); 605 argc = 0; 606 for (sp = arglist.list ; sp ; sp = sp->next) 607 argc++; 608 argv = stalloc(sizeof (char *) * (argc + 1)); 609 for (sp = arglist.list ; sp ; sp = sp->next) 610 *argv++ = sp->text; 611 *argv = NULL; 612 lastarg = NULL; 613 if (iflag && funcnest == 0 && argc > 0) 614 lastarg = argv[-1]; 615 argv -= argc; 616 617 /* Print the command if xflag is set. */ 618 if (xflag) { 619 outc('+', &errout); 620 for (sp = varlist.list ; sp ; sp = sp->next) { 621 outc(' ', &errout); 622 out2str(sp->text); 623 } 624 for (sp = arglist.list ; sp ; sp = sp->next) { 625 outc(' ', &errout); 626 out2str(sp->text); 627 } 628 outc('\n', &errout); 629 flushout(&errout); 630 } 631 632 /* Now locate the command. */ 633 if (argc == 0) { 634 cmdentry.cmdtype = CMDBUILTIN; 635 cmdentry.u.index = BLTINCMD; 636 } else { 637 find_command(argv[0], &cmdentry, 1); 638 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 639 exitstatus = 2; 640 flushout(&errout); 641 return; 642 } 643 /* implement the bltin builtin here */ 644 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 645 for (;;) { 646 argv++; 647 if (--argc == 0) 648 break; 649 if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 650 outfmt(&errout, "%s: not found\n", *argv); 651 exitstatus = 2; 652 flushout(&errout); 653 return; 654 } 655 if (cmdentry.u.index != BLTINCMD) 656 break; 657 } 658 } 659 } 660 661 /* Fork off a child process if necessary. */ 662 if (cmd->ncmd.backgnd 663 || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0 664 || (flags & EV_BACKCMD) != 0 665 && (cmdentry.cmdtype != CMDBUILTIN 666 || cmdentry.u.index == DOTCMD 667 || cmdentry.u.index == EVALCMD)) { 668 jp = makejob(cmd, 1); 669 mode = cmd->ncmd.backgnd; 670 if (flags & EV_BACKCMD) { 671 mode = FORK_NOJOB; 672 if (pipe(pip) < 0) 673 error("Pipe call failed"); 674 } 675 if (forkshell(jp, cmd, mode) != 0) 676 goto parent; /* at end of routine */ 677 if (flags & EV_BACKCMD) { 678 FORCEINTON; 679 close(pip[0]); 680 if (pip[1] != 1) { 681 close(1); 682 copyfd(pip[1], 1); 683 close(pip[1]); 684 } 685 } 686 flags |= EV_EXIT; 687 } 688 689 /* This is the child process if a fork occurred. */ 690 /* Execute the command. */ 691 if (cmdentry.cmdtype == CMDFUNCTION) { 692 trputs("Shell function: "); trargs(argv); 693 redirect(cmd->ncmd.redirect, REDIR_PUSH); 694 saveparam = shellparam; 695 shellparam.malloc = 0; 696 shellparam.nparam = argc - 1; 697 shellparam.p = argv + 1; 698 shellparam.optnext = NULL; 699 INTOFF; 700 savelocalvars = localvars; 701 localvars = NULL; 702 INTON; 703 if (setjmp(jmploc.loc)) { 704 if (exception == EXSHELLPROC) 705 freeparam((struct shparam *)&saveparam); 706 else { 707 freeparam(&shellparam); 708 shellparam = saveparam; 709 } 710 poplocalvars(); 711 localvars = savelocalvars; 712 handler = savehandler; 713 longjmp(handler->loc, 1); 714 } 715 savehandler = handler; 716 handler = &jmploc; 717 for (sp = varlist.list ; sp ; sp = sp->next) 718 mklocal(sp->text); 719 funcnest++; 720 evaltree(cmdentry.u.func, 0); 721 funcnest--; 722 INTOFF; 723 poplocalvars(); 724 localvars = savelocalvars; 725 freeparam(&shellparam); 726 shellparam = saveparam; 727 handler = savehandler; 728 popredir(); 729 INTON; 730 if (evalskip == SKIPFUNC) { 731 evalskip = 0; 732 skipcount = 0; 733 } 734 if (flags & EV_EXIT) 735 exitshell(exitstatus); 736 } else if (cmdentry.cmdtype == CMDBUILTIN) { 737 trputs("builtin command: "); trargs(argv); 738 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 739 if (flags == EV_BACKCMD) { 740 memout.nleft = 0; 741 memout.nextc = memout.buf; 742 memout.bufsize = 64; 743 mode |= REDIR_BACKQ; 744 } 745 redirect(cmd->ncmd.redirect, mode); 746 savecmdname = commandname; 747 cmdenviron = varlist.list; 748 e = -1; 749 if (setjmp(jmploc.loc)) { 750 e = exception; 751 exitstatus = (e == EXINT)? SIGINT+128 : 2; 752 goto cmddone; 753 } 754 savehandler = handler; 755 handler = &jmploc; 756 commandname = argv[0]; 757 argptr = argv + 1; 758 optptr = NULL; /* initialize nextopt */ 759 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 760 flushall(); 761 cmddone: 762 out1 = &output; 763 out2 = &errout; 764 freestdout(); 765 if (e != EXSHELLPROC) { 766 commandname = savecmdname; 767 if (flags & EV_EXIT) { 768 exitshell(exitstatus); 769 } 770 } 771 handler = savehandler; 772 if (e != -1) { 773 if (e != EXERROR || cmdentry.u.index == BLTINCMD 774 || cmdentry.u.index == DOTCMD 775 || cmdentry.u.index == EVALCMD 776 || cmdentry.u.index == EXECCMD) 777 exraise(e); 778 FORCEINTON; 779 } 780 if (cmdentry.u.index != EXECCMD) 781 popredir(); 782 if (flags == EV_BACKCMD) { 783 backcmd->buf = memout.buf; 784 backcmd->nleft = memout.nextc - memout.buf; 785 memout.buf = NULL; 786 } 787 } else { 788 trputs("normal command: "); trargs(argv); 789 clearredir(); 790 redirect(cmd->ncmd.redirect, 0); 791 if (varlist.list) { 792 p = stalloc(strlen(pathval()) + 1); 793 scopy(pathval(), p); 794 } else { 795 p = pathval(); 796 } 797 for (sp = varlist.list ; sp ; sp = sp->next) 798 setvareq(sp->text, VEXPORT|VSTACK); 799 envp = environment(); 800 shellexec(argv, envp, p, cmdentry.u.index); 801 /*NOTREACHED*/ 802 } 803 goto out; 804 805 parent: /* parent process gets here (if we forked) */ 806 if (mode == 0) { /* argument to fork */ 807 INTOFF; 808 exitstatus = waitforjob(jp); 809 INTON; 810 } else if (mode == 2) { 811 backcmd->fd = pip[0]; 812 close(pip[1]); 813 backcmd->jp = jp; 814 } 815 816 out: 817 if (lastarg) 818 setvar("_", lastarg, 0); 819 popstackmark(&smark); 820 } 821 822 823 824 /* 825 * Search for a command. This is called before we fork so that the 826 * location of the command will be available in the parent as well as 827 * the child. The check for "goodname" is an overly conservative 828 * check that the name will not be subject to expansion. 829 */ 830 831 STATIC void 832 prehash(n) 833 union node *n; 834 { 835 struct cmdentry entry; 836 837 if (n->type == NCMD && goodname(n->ncmd.args->narg.text)) 838 find_command(n->ncmd.args->narg.text, &entry, 0); 839 } 840 841 842 843 /* 844 * Builtin commands. Builtin commands whose functions are closely 845 * tied to evaluation are implemented here. 846 */ 847 848 /* 849 * No command given, or a bltin command with no arguments. Set the 850 * specified variables. 851 */ 852 853 bltincmd(argc, argv) char **argv; { 854 listsetvar(cmdenviron); 855 return exitstatus; 856 } 857 858 859 /* 860 * Handle break and continue commands. Break, continue, and return are 861 * all handled by setting the evalskip flag. The evaluation routines 862 * above all check this flag, and if it is set they start skipping 863 * commands rather than executing them. The variable skipcount is 864 * the number of loops to break/continue, or the number of function 865 * levels to return. (The latter is always 1.) It should probably 866 * be an error to break out of more loops than exist, but it isn't 867 * in the standard shell so we don't make it one here. 868 */ 869 870 breakcmd(argc, argv) char **argv; { 871 int n; 872 873 n = 1; 874 if (argc > 1) 875 n = number(argv[1]); 876 if (n > loopnest) 877 n = loopnest; 878 if (n > 0) { 879 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 880 skipcount = n; 881 } 882 return 0; 883 } 884 885 886 /* 887 * The return command. 888 */ 889 890 returncmd(argc, argv) char **argv; { 891 int ret; 892 893 ret = exitstatus; 894 if (argc > 1) 895 ret = number(argv[1]); 896 if (funcnest) { 897 evalskip = SKIPFUNC; 898 skipcount = 1; 899 } 900 return ret; 901 } 902 903 falsecmd(argc, argv) char **argv; { 904 return 1; 905 } 906 907 truecmd(argc, argv) char **argv; { 908 return 0; 909 } 910 911 912 execcmd(argc, argv) char **argv; { 913 if (argc > 1) { 914 iflag = 0; /* exit on error */ 915 setinteractive(0); 916 #if JOBS 917 jflag = 0; 918 setjobctl(0); 919 #endif 920 shellexec(argv + 1, environment(), pathval(), 0); 921 922 } 923 return 0; 924 } 925