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