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 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 36 #endif 37 #endif /* not lint */ 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <paths.h> 42 #include <signal.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <sys/resource.h> 46 #include <sys/wait.h> /* For WIFSIGNALED(status) */ 47 #include <errno.h> 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 int evalskip; /* set if we are skipping commands */ 78 STATIC int skipcount; /* number of levels to skip */ 79 MKINIT int loopnest; /* current loop nesting level */ 80 int funcnest; /* depth of function calls */ 81 STATIC int builtin_flags; /* evalcommand flags for builtins */ 82 83 84 char *commandname; 85 struct strlist *cmdenviron; 86 int exitstatus; /* exit status of last command */ 87 int oexitstatus; /* saved exit status */ 88 89 90 STATIC void evalloop(union node *, int); 91 STATIC void evalfor(union node *, int); 92 STATIC void evalcase(union node *, int); 93 STATIC void evalsubshell(union node *, int); 94 STATIC void evalredir(union node *, int); 95 STATIC void expredir(union node *); 96 STATIC void evalpipe(union node *); 97 STATIC void evalcommand(union node *, int, struct backcmd *); 98 STATIC void prehash(union node *); 99 100 101 /* 102 * Called to reset things after an exception. 103 */ 104 105 #ifdef mkinit 106 INCLUDE "eval.h" 107 108 RESET { 109 evalskip = 0; 110 loopnest = 0; 111 funcnest = 0; 112 } 113 114 SHELLPROC { 115 exitstatus = 0; 116 } 117 #endif 118 119 120 121 /* 122 * The eval command. 123 */ 124 125 int 126 evalcmd(int argc, char **argv) 127 { 128 char *p; 129 char *concat; 130 char **ap; 131 132 if (argc > 1) { 133 p = argv[1]; 134 if (argc > 2) { 135 STARTSTACKSTR(concat); 136 ap = argv + 2; 137 for (;;) { 138 while (*p) 139 STPUTC(*p++, concat); 140 if ((p = *ap++) == NULL) 141 break; 142 STPUTC(' ', concat); 143 } 144 STPUTC('\0', concat); 145 p = grabstackstr(concat); 146 } 147 evalstring(p, builtin_flags & EV_TESTED); 148 } else 149 exitstatus = 0; 150 return exitstatus; 151 } 152 153 154 /* 155 * Execute a command or commands contained in a string. 156 */ 157 158 void 159 evalstring(char *s, int flags) 160 { 161 union node *n; 162 struct stackmark smark; 163 int flags_exit; 164 int any; 165 166 flags_exit = flags & EV_EXIT; 167 flags &= ~EV_EXIT; 168 any = 0; 169 setstackmark(&smark); 170 setinputstring(s, 1); 171 while ((n = parsecmd(0)) != NEOF) { 172 if (n != NULL) { 173 if (flags_exit && preadateof()) 174 evaltree(n, flags | EV_EXIT); 175 else 176 evaltree(n, flags); 177 any = 1; 178 } 179 popstackmark(&smark); 180 } 181 popfile(); 182 popstackmark(&smark); 183 if (!any) 184 exitstatus = 0; 185 if (flags_exit) 186 exitshell(exitstatus); 187 } 188 189 190 /* 191 * Evaluate a parse tree. The value is left in the global variable 192 * exitstatus. 193 */ 194 195 void 196 evaltree(union node *n, int flags) 197 { 198 int do_etest; 199 200 do_etest = 0; 201 if (n == NULL) { 202 TRACE(("evaltree(NULL) called\n")); 203 exitstatus = 0; 204 goto out; 205 } 206 #ifndef NO_HISTORY 207 displayhist = 1; /* show history substitutions done with fc */ 208 #endif 209 TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type)); 210 switch (n->type) { 211 case NSEMI: 212 evaltree(n->nbinary.ch1, flags & ~EV_EXIT); 213 if (evalskip) 214 goto out; 215 evaltree(n->nbinary.ch2, flags); 216 break; 217 case NAND: 218 evaltree(n->nbinary.ch1, EV_TESTED); 219 if (evalskip || exitstatus != 0) { 220 goto out; 221 } 222 evaltree(n->nbinary.ch2, flags); 223 break; 224 case NOR: 225 evaltree(n->nbinary.ch1, EV_TESTED); 226 if (evalskip || exitstatus == 0) 227 goto out; 228 evaltree(n->nbinary.ch2, flags); 229 break; 230 case NREDIR: 231 evalredir(n, flags); 232 break; 233 case NSUBSHELL: 234 evalsubshell(n, flags); 235 do_etest = !(flags & EV_TESTED); 236 break; 237 case NBACKGND: 238 evalsubshell(n, flags); 239 break; 240 case NIF: { 241 evaltree(n->nif.test, EV_TESTED); 242 if (evalskip) 243 goto out; 244 if (exitstatus == 0) 245 evaltree(n->nif.ifpart, flags); 246 else if (n->nif.elsepart) 247 evaltree(n->nif.elsepart, flags); 248 else 249 exitstatus = 0; 250 break; 251 } 252 case NWHILE: 253 case NUNTIL: 254 evalloop(n, flags & ~EV_EXIT); 255 break; 256 case NFOR: 257 evalfor(n, flags & ~EV_EXIT); 258 break; 259 case NCASE: 260 evalcase(n, flags); 261 break; 262 case NDEFUN: 263 defun(n->narg.text, n->narg.next); 264 exitstatus = 0; 265 break; 266 case NNOT: 267 evaltree(n->nnot.com, EV_TESTED); 268 exitstatus = !exitstatus; 269 break; 270 271 case NPIPE: 272 evalpipe(n); 273 do_etest = !(flags & EV_TESTED); 274 break; 275 case NCMD: 276 evalcommand(n, flags, (struct backcmd *)NULL); 277 do_etest = !(flags & EV_TESTED); 278 break; 279 default: 280 out1fmt("Node type = %d\n", n->type); 281 flushout(&output); 282 break; 283 } 284 out: 285 if (pendingsigs) 286 dotrap(); 287 if ((flags & EV_EXIT) || (eflag && exitstatus != 0 && do_etest)) 288 exitshell(exitstatus); 289 } 290 291 292 STATIC void 293 evalloop(union node *n, int flags) 294 { 295 int status; 296 297 loopnest++; 298 status = 0; 299 for (;;) { 300 evaltree(n->nbinary.ch1, EV_TESTED); 301 if (evalskip) { 302 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 303 evalskip = 0; 304 continue; 305 } 306 if (evalskip == SKIPBREAK && --skipcount <= 0) 307 evalskip = 0; 308 if (evalskip == SKIPFUNC || evalskip == SKIPFILE) 309 status = exitstatus; 310 break; 311 } 312 if (n->type == NWHILE) { 313 if (exitstatus != 0) 314 break; 315 } else { 316 if (exitstatus == 0) 317 break; 318 } 319 evaltree(n->nbinary.ch2, flags); 320 status = exitstatus; 321 if (evalskip) 322 goto skipping; 323 } 324 loopnest--; 325 exitstatus = status; 326 } 327 328 329 330 STATIC void 331 evalfor(union node *n, int flags) 332 { 333 struct arglist arglist; 334 union node *argp; 335 struct strlist *sp; 336 struct stackmark smark; 337 338 setstackmark(&smark); 339 arglist.lastp = &arglist.list; 340 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 341 oexitstatus = exitstatus; 342 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 343 if (evalskip) 344 goto out; 345 } 346 *arglist.lastp = NULL; 347 348 exitstatus = 0; 349 loopnest++; 350 for (sp = arglist.list ; sp ; sp = sp->next) { 351 setvar(n->nfor.var, sp->text, 0); 352 evaltree(n->nfor.body, flags); 353 if (evalskip) { 354 if (evalskip == SKIPCONT && --skipcount <= 0) { 355 evalskip = 0; 356 continue; 357 } 358 if (evalskip == SKIPBREAK && --skipcount <= 0) 359 evalskip = 0; 360 break; 361 } 362 } 363 loopnest--; 364 out: 365 popstackmark(&smark); 366 } 367 368 369 370 STATIC void 371 evalcase(union node *n, int flags) 372 { 373 union node *cp; 374 union node *patp; 375 struct arglist arglist; 376 struct stackmark smark; 377 378 setstackmark(&smark); 379 arglist.lastp = &arglist.list; 380 oexitstatus = exitstatus; 381 exitstatus = 0; 382 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 383 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 384 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 385 if (casematch(patp, arglist.list->text)) { 386 if (evalskip == 0) { 387 evaltree(cp->nclist.body, flags); 388 } 389 goto out; 390 } 391 } 392 } 393 out: 394 popstackmark(&smark); 395 } 396 397 398 399 /* 400 * Kick off a subshell to evaluate a tree. 401 */ 402 403 STATIC void 404 evalsubshell(union node *n, int flags) 405 { 406 struct job *jp; 407 int backgnd = (n->type == NBACKGND); 408 409 expredir(n->nredir.redirect); 410 if ((!backgnd && flags & EV_EXIT && !have_traps()) || 411 forkshell(jp = makejob(n, 1), 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 } else if (! backgnd) { 417 INTOFF; 418 exitstatus = waitforjob(jp, (int *)NULL); 419 INTON; 420 } 421 } 422 423 424 /* 425 * Evaluate a redirected compound command. 426 */ 427 428 STATIC void 429 evalredir(union node *n, int flags) 430 { 431 struct jmploc jmploc; 432 struct jmploc *savehandler; 433 volatile int in_redirect = 1; 434 435 expredir(n->nredir.redirect); 436 savehandler = handler; 437 if (setjmp(jmploc.loc)) { 438 int e; 439 440 handler = savehandler; 441 e = exception; 442 if (e == EXERROR || e == EXEXEC) { 443 popredir(); 444 if (in_redirect) { 445 exitstatus = 2; 446 return; 447 } 448 } 449 longjmp(handler->loc, 1); 450 } else { 451 INTOFF; 452 handler = &jmploc; 453 redirect(n->nredir.redirect, REDIR_PUSH); 454 in_redirect = 0; 455 INTON; 456 evaltree(n->nredir.n, flags); 457 } 458 INTOFF; 459 handler = savehandler; 460 popredir(); 461 INTON; 462 } 463 464 465 /* 466 * Compute the names of the files in a redirection list. 467 */ 468 469 STATIC void 470 expredir(union node *n) 471 { 472 union node *redir; 473 474 for (redir = n ; redir ; redir = redir->nfile.next) { 475 struct arglist fn; 476 fn.lastp = &fn.list; 477 oexitstatus = exitstatus; 478 switch (redir->type) { 479 case NFROM: 480 case NTO: 481 case NFROMTO: 482 case NAPPEND: 483 case NCLOBBER: 484 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 485 redir->nfile.expfname = fn.list->text; 486 break; 487 case NFROMFD: 488 case NTOFD: 489 if (redir->ndup.vname) { 490 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); 491 fixredir(redir, fn.list->text, 1); 492 } 493 break; 494 } 495 } 496 } 497 498 499 500 /* 501 * Evaluate a pipeline. All the processes in the pipeline are children 502 * of the process creating the pipeline. (This differs from some versions 503 * of the shell, which make the last process in a pipeline the parent 504 * of all the rest.) 505 */ 506 507 STATIC void 508 evalpipe(union node *n) 509 { 510 struct job *jp; 511 struct nodelist *lp; 512 int pipelen; 513 int prevfd; 514 int pip[2]; 515 516 TRACE(("evalpipe(%p) called\n", (void *)n)); 517 pipelen = 0; 518 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 519 pipelen++; 520 INTOFF; 521 jp = makejob(n, pipelen); 522 prevfd = -1; 523 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 524 prehash(lp->n); 525 pip[1] = -1; 526 if (lp->next) { 527 if (pipe(pip) < 0) { 528 close(prevfd); 529 error("Pipe call failed: %s", strerror(errno)); 530 } 531 } 532 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 533 INTON; 534 if (prevfd > 0) { 535 dup2(prevfd, 0); 536 close(prevfd); 537 } 538 if (pip[1] >= 0) { 539 if (!(prevfd >= 0 && pip[0] == 0)) 540 close(pip[0]); 541 if (pip[1] != 1) { 542 dup2(pip[1], 1); 543 close(pip[1]); 544 } 545 } 546 evaltree(lp->n, EV_EXIT); 547 } 548 if (prevfd >= 0) 549 close(prevfd); 550 prevfd = pip[0]; 551 close(pip[1]); 552 } 553 INTON; 554 if (n->npipe.backgnd == 0) { 555 INTOFF; 556 exitstatus = waitforjob(jp, (int *)NULL); 557 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 558 INTON; 559 } 560 } 561 562 563 564 /* 565 * Execute a command inside back quotes. If it's a builtin command, we 566 * want to save its output in a block obtained from malloc. Otherwise 567 * we fork off a subprocess and get the output of the command via a pipe. 568 * Should be called with interrupts off. 569 */ 570 571 void 572 evalbackcmd(union node *n, struct backcmd *result) 573 { 574 int pip[2]; 575 struct job *jp; 576 struct stackmark smark; /* unnecessary */ 577 578 setstackmark(&smark); 579 result->fd = -1; 580 result->buf = NULL; 581 result->nleft = 0; 582 result->jp = NULL; 583 if (n == NULL) { 584 exitstatus = 0; 585 goto out; 586 } 587 if (n->type == NCMD) { 588 exitstatus = oexitstatus; 589 evalcommand(n, EV_BACKCMD, result); 590 } else { 591 exitstatus = 0; 592 if (pipe(pip) < 0) 593 error("Pipe call failed: %s", strerror(errno)); 594 jp = makejob(n, 1); 595 if (forkshell(jp, n, FORK_NOJOB) == 0) { 596 FORCEINTON; 597 close(pip[0]); 598 if (pip[1] != 1) { 599 dup2(pip[1], 1); 600 close(pip[1]); 601 } 602 evaltree(n, EV_EXIT); 603 } 604 close(pip[1]); 605 result->fd = pip[0]; 606 result->jp = jp; 607 } 608 out: 609 popstackmark(&smark); 610 TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n", 611 result->fd, result->buf, result->nleft, result->jp)); 612 } 613 614 615 616 /* 617 * Execute a simple command. 618 */ 619 620 STATIC void 621 evalcommand(union node *cmd, int flags, struct backcmd *backcmd) 622 { 623 struct stackmark smark; 624 union node *argp; 625 struct arglist arglist; 626 struct arglist varlist; 627 char **argv; 628 int argc; 629 char **envp; 630 int varflag; 631 struct strlist *sp; 632 int mode; 633 int pip[2]; 634 struct cmdentry cmdentry; 635 struct job *jp; 636 struct jmploc jmploc; 637 struct jmploc *savehandler; 638 char *savecmdname; 639 struct shparam saveparam; 640 struct localvar *savelocalvars; 641 struct parsefile *savetopfile; 642 volatile int e; 643 char *lastarg; 644 int realstatus; 645 int do_clearcmdentry; 646 const char *path = pathval(); 647 648 /* First expand the arguments. */ 649 TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags)); 650 setstackmark(&smark); 651 arglist.lastp = &arglist.list; 652 varlist.lastp = &varlist.list; 653 varflag = 1; 654 do_clearcmdentry = 0; 655 oexitstatus = exitstatus; 656 exitstatus = 0; 657 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 658 char *p = argp->narg.text; 659 if (varflag && is_name(*p)) { 660 do { 661 p++; 662 } while (is_in_name(*p)); 663 if (*p == '=') { 664 expandarg(argp, &varlist, EXP_VARTILDE); 665 continue; 666 } 667 } 668 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 669 varflag = 0; 670 } 671 *arglist.lastp = NULL; 672 *varlist.lastp = NULL; 673 expredir(cmd->ncmd.redirect); 674 argc = 0; 675 for (sp = arglist.list ; sp ; sp = sp->next) 676 argc++; 677 argv = stalloc(sizeof (char *) * (argc + 1)); 678 679 for (sp = arglist.list ; sp ; sp = sp->next) { 680 TRACE(("evalcommand arg: %s\n", sp->text)); 681 *argv++ = sp->text; 682 } 683 *argv = NULL; 684 lastarg = NULL; 685 if (iflag && funcnest == 0 && argc > 0) 686 lastarg = argv[-1]; 687 argv -= argc; 688 689 /* Print the command if xflag is set. */ 690 if (xflag) { 691 char sep = 0; 692 const char *p; 693 out2str(ps4val()); 694 for (sp = varlist.list ; sp ; sp = sp->next) { 695 if (sep != 0) 696 out2c(' '); 697 p = sp->text; 698 while (*p != '=' && *p != '\0') 699 out2c(*p++); 700 if (*p != '\0') { 701 out2c(*p++); 702 out2qstr(p); 703 } 704 sep = ' '; 705 } 706 for (sp = arglist.list ; sp ; sp = sp->next) { 707 if (sep != 0) 708 out2c(' '); 709 /* Disambiguate command looking like assignment. */ 710 if (sp == arglist.list && 711 strchr(sp->text, '=') != NULL && 712 strchr(sp->text, '\'') == NULL) { 713 out2c('\''); 714 out2str(sp->text); 715 out2c('\''); 716 } else 717 out2qstr(sp->text); 718 sep = ' '; 719 } 720 out2c('\n'); 721 flushout(&errout); 722 } 723 724 /* Now locate the command. */ 725 if (argc == 0) { 726 /* Variable assignment(s) without command */ 727 cmdentry.cmdtype = CMDBUILTIN; 728 cmdentry.u.index = BLTINCMD; 729 cmdentry.special = 0; 730 } else { 731 static const char PATH[] = "PATH="; 732 int cmd_flags = 0, bltinonly = 0; 733 734 /* 735 * Modify the command lookup path, if a PATH= assignment 736 * is present 737 */ 738 for (sp = varlist.list ; sp ; sp = sp->next) 739 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { 740 path = sp->text + sizeof(PATH) - 1; 741 /* 742 * On `PATH=... command`, we need to make 743 * sure that the command isn't using the 744 * non-updated hash table of the outer PATH 745 * setting and we need to make sure that 746 * the hash table isn't filled with items 747 * from the temporary setting. 748 * 749 * It would be better to forbit using and 750 * updating the table while this command 751 * runs, by the command finding mechanism 752 * is heavily integrated with hash handling, 753 * so we just delete the hash before and after 754 * the command runs. Partly deleting like 755 * changepatch() does doesn't seem worth the 756 * bookinging effort, since most such runs add 757 * directories in front of the new PATH. 758 */ 759 clearcmdentry(0); 760 do_clearcmdentry = 1; 761 } 762 763 for (;;) { 764 if (bltinonly) { 765 cmdentry.u.index = find_builtin(*argv, &cmdentry.special); 766 if (cmdentry.u.index < 0) { 767 cmdentry.u.index = BLTINCMD; 768 argv--; 769 argc++; 770 break; 771 } 772 } else 773 find_command(argv[0], &cmdentry, cmd_flags, path); 774 /* implement the bltin and command builtins here */ 775 if (cmdentry.cmdtype != CMDBUILTIN) 776 break; 777 if (cmdentry.u.index == BLTINCMD) { 778 if (argc == 1) 779 break; 780 argv++; 781 argc--; 782 bltinonly = 1; 783 } else if (cmdentry.u.index == COMMANDCMD) { 784 if (argc == 1) 785 break; 786 if (!strcmp(argv[1], "-p")) { 787 if (argc == 2) 788 break; 789 if (argv[2][0] == '-') { 790 if (strcmp(argv[2], "--")) 791 break; 792 if (argc == 3) 793 break; 794 argv += 3; 795 argc -= 3; 796 } else { 797 argv += 2; 798 argc -= 2; 799 } 800 path = _PATH_STDPATH; 801 clearcmdentry(0); 802 do_clearcmdentry = 1; 803 } else if (!strcmp(argv[1], "--")) { 804 if (argc == 2) 805 break; 806 argv += 2; 807 argc -= 2; 808 } else if (argv[1][0] == '-') 809 break; 810 else { 811 argv++; 812 argc--; 813 } 814 cmd_flags |= DO_NOFUNC; 815 bltinonly = 0; 816 } else 817 break; 818 } 819 /* 820 * Special builtins lose their special properties when 821 * called via 'command'. 822 */ 823 if (cmd_flags & DO_NOFUNC) 824 cmdentry.special = 0; 825 } 826 827 /* Fork off a child process if necessary. */ 828 if (cmd->ncmd.backgnd 829 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) 830 && ((flags & EV_EXIT) == 0 || have_traps())) 831 || ((flags & EV_BACKCMD) != 0 832 && (cmdentry.cmdtype != CMDBUILTIN 833 || cmdentry.u.index == CDCMD 834 || cmdentry.u.index == DOTCMD 835 || cmdentry.u.index == EVALCMD))) { 836 jp = makejob(cmd, 1); 837 mode = cmd->ncmd.backgnd; 838 if (flags & EV_BACKCMD) { 839 mode = FORK_NOJOB; 840 if (pipe(pip) < 0) 841 error("Pipe call failed: %s", strerror(errno)); 842 } 843 if (forkshell(jp, cmd, mode) != 0) 844 goto parent; /* at end of routine */ 845 if (flags & EV_BACKCMD) { 846 FORCEINTON; 847 close(pip[0]); 848 if (pip[1] != 1) { 849 dup2(pip[1], 1); 850 close(pip[1]); 851 } 852 } 853 flags |= EV_EXIT; 854 } 855 856 /* This is the child process if a fork occurred. */ 857 /* Execute the command. */ 858 if (cmdentry.cmdtype == CMDFUNCTION) { 859 #ifdef DEBUG 860 trputs("Shell function: "); trargs(argv); 861 #endif 862 saveparam = shellparam; 863 shellparam.malloc = 0; 864 shellparam.reset = 1; 865 shellparam.nparam = argc - 1; 866 shellparam.p = argv + 1; 867 shellparam.optnext = NULL; 868 INTOFF; 869 savelocalvars = localvars; 870 localvars = NULL; 871 reffunc(cmdentry.u.func); 872 savehandler = handler; 873 if (setjmp(jmploc.loc)) { 874 if (exception == EXSHELLPROC) 875 freeparam(&saveparam); 876 else { 877 freeparam(&shellparam); 878 shellparam = saveparam; 879 if (exception == EXERROR || exception == EXEXEC) 880 popredir(); 881 } 882 unreffunc(cmdentry.u.func); 883 poplocalvars(); 884 localvars = savelocalvars; 885 funcnest--; 886 handler = savehandler; 887 longjmp(handler->loc, 1); 888 } 889 handler = &jmploc; 890 funcnest++; 891 redirect(cmd->ncmd.redirect, REDIR_PUSH); 892 INTON; 893 for (sp = varlist.list ; sp ; sp = sp->next) 894 mklocal(sp->text); 895 exitstatus = oexitstatus; 896 if (flags & EV_TESTED) 897 evaltree(getfuncnode(cmdentry.u.func), EV_TESTED); 898 else 899 evaltree(getfuncnode(cmdentry.u.func), 0); 900 INTOFF; 901 unreffunc(cmdentry.u.func); 902 poplocalvars(); 903 localvars = savelocalvars; 904 freeparam(&shellparam); 905 shellparam = saveparam; 906 handler = savehandler; 907 funcnest--; 908 popredir(); 909 INTON; 910 if (evalskip == SKIPFUNC) { 911 evalskip = 0; 912 skipcount = 0; 913 } 914 if (flags & EV_EXIT) 915 exitshell(exitstatus); 916 } else if (cmdentry.cmdtype == CMDBUILTIN) { 917 #ifdef DEBUG 918 trputs("builtin command: "); trargs(argv); 919 #endif 920 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 921 if (flags == EV_BACKCMD) { 922 memout.nleft = 0; 923 memout.nextc = memout.buf; 924 memout.bufsize = 64; 925 mode |= REDIR_BACKQ; 926 cmdentry.special = 0; 927 } 928 savecmdname = commandname; 929 savetopfile = getcurrentfile(); 930 cmdenviron = varlist.list; 931 e = -1; 932 savehandler = handler; 933 if (setjmp(jmploc.loc)) { 934 e = exception; 935 exitstatus = (e == EXINT)? SIGINT+128 : 2; 936 goto cmddone; 937 } 938 handler = &jmploc; 939 redirect(cmd->ncmd.redirect, mode); 940 /* 941 * If there is no command word, redirection errors should 942 * not be fatal but assignment errors should. 943 */ 944 if (argc == 0 && !(flags & EV_BACKCMD)) 945 cmdentry.special = 1; 946 if (cmdentry.special) 947 listsetvar(cmdenviron); 948 if (argc > 0) 949 bltinsetlocale(); 950 commandname = argv[0]; 951 argptr = argv + 1; 952 nextopt_optptr = NULL; /* initialize nextopt */ 953 builtin_flags = flags; 954 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 955 flushall(); 956 cmddone: 957 if (argc > 0) 958 bltinunsetlocale(); 959 cmdenviron = NULL; 960 out1 = &output; 961 out2 = &errout; 962 freestdout(); 963 if (e != EXSHELLPROC) { 964 commandname = savecmdname; 965 if (flags & EV_EXIT) { 966 exitshell(exitstatus); 967 } 968 } 969 handler = savehandler; 970 if (flags == EV_BACKCMD) { 971 backcmd->buf = memout.buf; 972 backcmd->nleft = memout.nextc - memout.buf; 973 memout.buf = NULL; 974 } 975 if (cmdentry.u.index != EXECCMD && 976 (e == -1 || e == EXERROR || e == EXEXEC)) 977 popredir(); 978 if (e != -1) { 979 if ((e != EXERROR && e != EXEXEC) 980 || cmdentry.special) 981 exraise(e); 982 popfilesupto(savetopfile); 983 if (flags != EV_BACKCMD) 984 FORCEINTON; 985 } 986 } else { 987 #ifdef DEBUG 988 trputs("normal command: "); trargs(argv); 989 #endif 990 redirect(cmd->ncmd.redirect, 0); 991 for (sp = varlist.list ; sp ; sp = sp->next) 992 setvareq(sp->text, VEXPORT|VSTACK); 993 envp = environment(); 994 shellexec(argv, envp, path, cmdentry.u.index); 995 /*NOTREACHED*/ 996 } 997 goto out; 998 999 parent: /* parent process gets here (if we forked) */ 1000 if (mode == FORK_FG) { /* argument to fork */ 1001 INTOFF; 1002 exitstatus = waitforjob(jp, &realstatus); 1003 INTON; 1004 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 1005 evalskip = SKIPBREAK; 1006 skipcount = loopnest; 1007 } 1008 } else if (mode == FORK_NOJOB) { 1009 backcmd->fd = pip[0]; 1010 close(pip[1]); 1011 backcmd->jp = jp; 1012 } 1013 1014 out: 1015 if (lastarg) 1016 setvar("_", lastarg, 0); 1017 if (do_clearcmdentry) 1018 clearcmdentry(0); 1019 popstackmark(&smark); 1020 } 1021 1022 1023 1024 /* 1025 * Search for a command. This is called before we fork so that the 1026 * location of the command will be available in the parent as well as 1027 * the child. The check for "goodname" is an overly conservative 1028 * check that the name will not be subject to expansion. 1029 */ 1030 1031 STATIC void 1032 prehash(union node *n) 1033 { 1034 struct cmdentry entry; 1035 1036 if (n && n->type == NCMD && n->ncmd.args) 1037 if (goodname(n->ncmd.args->narg.text)) 1038 find_command(n->ncmd.args->narg.text, &entry, 0, 1039 pathval()); 1040 } 1041 1042 1043 1044 /* 1045 * Builtin commands. Builtin commands whose functions are closely 1046 * tied to evaluation are implemented here. 1047 */ 1048 1049 /* 1050 * No command given, a bltin command with no arguments, or a bltin command 1051 * with an invalid name. 1052 */ 1053 1054 int 1055 bltincmd(int argc, char **argv) 1056 { 1057 if (argc > 1) { 1058 out2fmt_flush("%s: not found\n", argv[1]); 1059 return 127; 1060 } 1061 /* 1062 * Preserve exitstatus of a previous possible redirection 1063 * as POSIX mandates 1064 */ 1065 return exitstatus; 1066 } 1067 1068 1069 /* 1070 * Handle break and continue commands. Break, continue, and return are 1071 * all handled by setting the evalskip flag. The evaluation routines 1072 * above all check this flag, and if it is set they start skipping 1073 * commands rather than executing them. The variable skipcount is 1074 * the number of loops to break/continue, or the number of function 1075 * levels to return. (The latter is always 1.) It should probably 1076 * be an error to break out of more loops than exist, but it isn't 1077 * in the standard shell so we don't make it one here. 1078 */ 1079 1080 int 1081 breakcmd(int argc, char **argv) 1082 { 1083 int n = argc > 1 ? number(argv[1]) : 1; 1084 1085 if (n > loopnest) 1086 n = loopnest; 1087 if (n > 0) { 1088 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1089 skipcount = n; 1090 } 1091 return 0; 1092 } 1093 1094 /* 1095 * The `command' command. 1096 */ 1097 int 1098 commandcmd(int argc, char **argv) 1099 { 1100 const char *path; 1101 int ch; 1102 int cmd = -1; 1103 1104 path = bltinlookup("PATH", 1); 1105 1106 optind = optreset = 1; 1107 opterr = 0; 1108 while ((ch = getopt(argc, argv, "pvV")) != -1) { 1109 switch (ch) { 1110 case 'p': 1111 path = _PATH_STDPATH; 1112 break; 1113 case 'v': 1114 cmd = TYPECMD_SMALLV; 1115 break; 1116 case 'V': 1117 cmd = TYPECMD_BIGV; 1118 break; 1119 case '?': 1120 default: 1121 error("unknown option: -%c", optopt); 1122 } 1123 } 1124 argc -= optind; 1125 argv += optind; 1126 1127 if (cmd != -1) { 1128 if (argc != 1) 1129 error("wrong number of arguments"); 1130 return typecmd_impl(2, argv - 1, cmd, path); 1131 } 1132 if (argc != 0) 1133 error("commandcmd() called while it should not be"); 1134 1135 /* 1136 * Do nothing successfully if no command was specified; 1137 * ksh also does this. 1138 */ 1139 return 0; 1140 } 1141 1142 1143 /* 1144 * The return command. 1145 */ 1146 1147 int 1148 returncmd(int argc, char **argv) 1149 { 1150 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 1151 1152 if (funcnest) { 1153 evalskip = SKIPFUNC; 1154 skipcount = 1; 1155 } else { 1156 /* skip the rest of the file */ 1157 evalskip = SKIPFILE; 1158 skipcount = 1; 1159 } 1160 return ret; 1161 } 1162 1163 1164 int 1165 falsecmd(int argc __unused, char **argv __unused) 1166 { 1167 return 1; 1168 } 1169 1170 1171 int 1172 truecmd(int argc __unused, char **argv __unused) 1173 { 1174 return 0; 1175 } 1176 1177 1178 int 1179 execcmd(int argc, char **argv) 1180 { 1181 /* 1182 * Because we have historically not supported any options, 1183 * only treat "--" specially. 1184 */ 1185 if (argc > 1 && strcmp(argv[1], "--") == 0) 1186 argc--, argv++; 1187 if (argc > 1) { 1188 struct strlist *sp; 1189 1190 iflag = 0; /* exit on error */ 1191 mflag = 0; 1192 optschanged(); 1193 for (sp = cmdenviron; sp ; sp = sp->next) 1194 setvareq(sp->text, VEXPORT|VSTACK); 1195 shellexec(argv + 1, environment(), pathval(), 0); 1196 1197 } 1198 return 0; 1199 } 1200 1201 1202 int 1203 timescmd(int argc __unused, char **argv __unused) 1204 { 1205 struct rusage ru; 1206 long shumins, shsmins, chumins, chsmins; 1207 double shusecs, shssecs, chusecs, chssecs; 1208 1209 if (getrusage(RUSAGE_SELF, &ru) < 0) 1210 return 1; 1211 shumins = ru.ru_utime.tv_sec / 60; 1212 shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1213 shsmins = ru.ru_stime.tv_sec / 60; 1214 shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1215 if (getrusage(RUSAGE_CHILDREN, &ru) < 0) 1216 return 1; 1217 chumins = ru.ru_utime.tv_sec / 60; 1218 chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1219 chsmins = ru.ru_stime.tv_sec / 60; 1220 chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1221 out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins, 1222 shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs); 1223 return 0; 1224 } 1225