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