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