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