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