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