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 break; 309 } 310 if (n->type == NWHILE) { 311 if (exitstatus != 0) 312 break; 313 } else { 314 if (exitstatus == 0) 315 break; 316 } 317 evaltree(n->nbinary.ch2, flags); 318 status = exitstatus; 319 if (evalskip) 320 goto skipping; 321 } 322 loopnest--; 323 exitstatus = status; 324 } 325 326 327 328 STATIC void 329 evalfor(union node *n, int flags) 330 { 331 struct arglist arglist; 332 union node *argp; 333 struct strlist *sp; 334 struct stackmark smark; 335 336 setstackmark(&smark); 337 arglist.lastp = &arglist.list; 338 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 339 oexitstatus = exitstatus; 340 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 341 if (evalskip) 342 goto out; 343 } 344 *arglist.lastp = NULL; 345 346 exitstatus = 0; 347 loopnest++; 348 for (sp = arglist.list ; sp ; sp = sp->next) { 349 setvar(n->nfor.var, sp->text, 0); 350 evaltree(n->nfor.body, flags); 351 if (evalskip) { 352 if (evalskip == SKIPCONT && --skipcount <= 0) { 353 evalskip = 0; 354 continue; 355 } 356 if (evalskip == SKIPBREAK && --skipcount <= 0) 357 evalskip = 0; 358 break; 359 } 360 } 361 loopnest--; 362 out: 363 popstackmark(&smark); 364 } 365 366 367 368 STATIC void 369 evalcase(union node *n, int flags) 370 { 371 union node *cp; 372 union node *patp; 373 struct arglist arglist; 374 struct stackmark smark; 375 376 setstackmark(&smark); 377 arglist.lastp = &arglist.list; 378 oexitstatus = exitstatus; 379 exitstatus = 0; 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(union node *n, int flags) 403 { 404 struct job *jp; 405 int backgnd = (n->type == NBACKGND); 406 407 expredir(n->nredir.redirect); 408 if ((!backgnd && flags & EV_EXIT && !have_traps()) || 409 forkshell(jp = makejob(n, 1), n, backgnd) == 0) { 410 if (backgnd) 411 flags &=~ EV_TESTED; 412 redirect(n->nredir.redirect, 0); 413 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 414 } else if (! backgnd) { 415 INTOFF; 416 exitstatus = waitforjob(jp, (int *)NULL); 417 INTON; 418 } 419 } 420 421 422 /* 423 * Evaluate a redirected compound command. 424 */ 425 426 STATIC void 427 evalredir(union node *n, int flags) 428 { 429 struct jmploc jmploc; 430 struct jmploc *savehandler; 431 volatile int in_redirect = 1; 432 433 expredir(n->nredir.redirect); 434 savehandler = handler; 435 if (setjmp(jmploc.loc)) { 436 int e; 437 438 handler = savehandler; 439 e = exception; 440 if (e == EXERROR || e == EXEXEC) { 441 popredir(); 442 if (in_redirect) { 443 exitstatus = 2; 444 return; 445 } 446 } 447 longjmp(handler->loc, 1); 448 } else { 449 INTOFF; 450 handler = &jmploc; 451 redirect(n->nredir.redirect, REDIR_PUSH); 452 in_redirect = 0; 453 INTON; 454 evaltree(n->nredir.n, flags); 455 } 456 INTOFF; 457 handler = savehandler; 458 popredir(); 459 INTON; 460 } 461 462 463 /* 464 * Compute the names of the files in a redirection list. 465 */ 466 467 STATIC void 468 expredir(union node *n) 469 { 470 union node *redir; 471 472 for (redir = n ; redir ; redir = redir->nfile.next) { 473 struct arglist fn; 474 fn.lastp = &fn.list; 475 oexitstatus = exitstatus; 476 switch (redir->type) { 477 case NFROM: 478 case NTO: 479 case NFROMTO: 480 case NAPPEND: 481 case NCLOBBER: 482 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 483 redir->nfile.expfname = fn.list->text; 484 break; 485 case NFROMFD: 486 case NTOFD: 487 if (redir->ndup.vname) { 488 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); 489 fixredir(redir, fn.list->text, 1); 490 } 491 break; 492 } 493 } 494 } 495 496 497 498 /* 499 * Evaluate a pipeline. All the processes in the pipeline are children 500 * of the process creating the pipeline. (This differs from some versions 501 * of the shell, which make the last process in a pipeline the parent 502 * of all the rest.) 503 */ 504 505 STATIC void 506 evalpipe(union node *n) 507 { 508 struct job *jp; 509 struct nodelist *lp; 510 int pipelen; 511 int prevfd; 512 int pip[2]; 513 514 TRACE(("evalpipe(%p) called\n", (void *)n)); 515 pipelen = 0; 516 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 517 pipelen++; 518 INTOFF; 519 jp = makejob(n, pipelen); 520 prevfd = -1; 521 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 522 prehash(lp->n); 523 pip[1] = -1; 524 if (lp->next) { 525 if (pipe(pip) < 0) { 526 close(prevfd); 527 error("Pipe call failed: %s", strerror(errno)); 528 } 529 } 530 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 531 INTON; 532 if (prevfd > 0) { 533 dup2(prevfd, 0); 534 close(prevfd); 535 } 536 if (pip[1] >= 0) { 537 if (!(prevfd >= 0 && pip[0] == 0)) 538 close(pip[0]); 539 if (pip[1] != 1) { 540 dup2(pip[1], 1); 541 close(pip[1]); 542 } 543 } 544 evaltree(lp->n, EV_EXIT); 545 } 546 if (prevfd >= 0) 547 close(prevfd); 548 prevfd = pip[0]; 549 close(pip[1]); 550 } 551 INTON; 552 if (n->npipe.backgnd == 0) { 553 INTOFF; 554 exitstatus = waitforjob(jp, (int *)NULL); 555 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 556 INTON; 557 } 558 } 559 560 561 562 /* 563 * Execute a command inside back quotes. If it's a builtin command, we 564 * want to save its output in a block obtained from malloc. Otherwise 565 * we fork off a subprocess and get the output of the command via a pipe. 566 * Should be called with interrupts off. 567 */ 568 569 void 570 evalbackcmd(union node *n, struct backcmd *result) 571 { 572 int pip[2]; 573 struct job *jp; 574 struct stackmark smark; /* unnecessary */ 575 576 setstackmark(&smark); 577 result->fd = -1; 578 result->buf = NULL; 579 result->nleft = 0; 580 result->jp = NULL; 581 if (n == NULL) { 582 exitstatus = 0; 583 goto out; 584 } 585 if (n->type == NCMD) { 586 exitstatus = oexitstatus; 587 evalcommand(n, EV_BACKCMD, result); 588 } else { 589 exitstatus = 0; 590 if (pipe(pip) < 0) 591 error("Pipe call failed: %s", strerror(errno)); 592 jp = makejob(n, 1); 593 if (forkshell(jp, n, FORK_NOJOB) == 0) { 594 FORCEINTON; 595 close(pip[0]); 596 if (pip[1] != 1) { 597 dup2(pip[1], 1); 598 close(pip[1]); 599 } 600 evaltree(n, EV_EXIT); 601 } 602 close(pip[1]); 603 result->fd = pip[0]; 604 result->jp = jp; 605 } 606 out: 607 popstackmark(&smark); 608 TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n", 609 result->fd, result->buf, result->nleft, result->jp)); 610 } 611 612 613 614 /* 615 * Execute a simple command. 616 */ 617 618 STATIC void 619 evalcommand(union node *cmd, int flags, struct backcmd *backcmd) 620 { 621 struct stackmark smark; 622 union node *argp; 623 struct arglist arglist; 624 struct arglist varlist; 625 char **argv; 626 int argc; 627 char **envp; 628 int varflag; 629 struct strlist *sp; 630 int mode; 631 int pip[2]; 632 struct cmdentry cmdentry; 633 struct job *jp; 634 struct jmploc jmploc; 635 struct jmploc *savehandler; 636 char *savecmdname; 637 struct shparam saveparam; 638 struct localvar *savelocalvars; 639 struct parsefile *savetopfile; 640 volatile int e; 641 char *lastarg; 642 int realstatus; 643 int do_clearcmdentry; 644 const char *path = pathval(); 645 646 /* First expand the arguments. */ 647 TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags)); 648 setstackmark(&smark); 649 arglist.lastp = &arglist.list; 650 varlist.lastp = &varlist.list; 651 varflag = 1; 652 do_clearcmdentry = 0; 653 oexitstatus = exitstatus; 654 exitstatus = 0; 655 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 656 char *p = argp->narg.text; 657 if (varflag && is_name(*p)) { 658 do { 659 p++; 660 } while (is_in_name(*p)); 661 if (*p == '=') { 662 expandarg(argp, &varlist, EXP_VARTILDE); 663 continue; 664 } 665 } 666 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 667 varflag = 0; 668 } 669 *arglist.lastp = NULL; 670 *varlist.lastp = NULL; 671 expredir(cmd->ncmd.redirect); 672 argc = 0; 673 for (sp = arglist.list ; sp ; sp = sp->next) 674 argc++; 675 argv = stalloc(sizeof (char *) * (argc + 1)); 676 677 for (sp = arglist.list ; sp ; sp = sp->next) { 678 TRACE(("evalcommand arg: %s\n", sp->text)); 679 *argv++ = sp->text; 680 } 681 *argv = NULL; 682 lastarg = NULL; 683 if (iflag && funcnest == 0 && argc > 0) 684 lastarg = argv[-1]; 685 argv -= argc; 686 687 /* Print the command if xflag is set. */ 688 if (xflag) { 689 char sep = 0; 690 const char *p; 691 out2str(ps4val()); 692 for (sp = varlist.list ; sp ; sp = sp->next) { 693 if (sep != 0) 694 out2c(' '); 695 p = sp->text; 696 while (*p != '=' && *p != '\0') 697 out2c(*p++); 698 if (*p != '\0') { 699 out2c(*p++); 700 out2qstr(p); 701 } 702 sep = ' '; 703 } 704 for (sp = arglist.list ; sp ; sp = sp->next) { 705 if (sep != 0) 706 out2c(' '); 707 /* Disambiguate command looking like assignment. */ 708 if (sp == arglist.list && 709 strchr(sp->text, '=') != NULL && 710 strchr(sp->text, '\'') == NULL) { 711 out2c('\''); 712 out2str(sp->text); 713 out2c('\''); 714 } else 715 out2qstr(sp->text); 716 sep = ' '; 717 } 718 out2c('\n'); 719 flushout(&errout); 720 } 721 722 /* Now locate the command. */ 723 if (argc == 0) { 724 /* Variable assignment(s) without command */ 725 cmdentry.cmdtype = CMDBUILTIN; 726 cmdentry.u.index = BLTINCMD; 727 cmdentry.special = 0; 728 } else { 729 static const char PATH[] = "PATH="; 730 int cmd_flags = 0, bltinonly = 0; 731 732 /* 733 * Modify the command lookup path, if a PATH= assignment 734 * is present 735 */ 736 for (sp = varlist.list ; sp ; sp = sp->next) 737 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { 738 path = sp->text + sizeof(PATH) - 1; 739 /* 740 * On `PATH=... command`, we need to make 741 * sure that the command isn't using the 742 * non-updated hash table of the outer PATH 743 * setting and we need to make sure that 744 * the hash table isn't filled with items 745 * from the temporary setting. 746 * 747 * It would be better to forbit using and 748 * updating the table while this command 749 * runs, by the command finding mechanism 750 * is heavily integrated with hash handling, 751 * so we just delete the hash before and after 752 * the command runs. Partly deleting like 753 * changepatch() does doesn't seem worth the 754 * bookinging effort, since most such runs add 755 * directories in front of the new PATH. 756 */ 757 clearcmdentry(0); 758 do_clearcmdentry = 1; 759 } 760 761 for (;;) { 762 if (bltinonly) { 763 cmdentry.u.index = find_builtin(*argv, &cmdentry.special); 764 if (cmdentry.u.index < 0) { 765 cmdentry.u.index = BLTINCMD; 766 argv--; 767 argc++; 768 break; 769 } 770 } else 771 find_command(argv[0], &cmdentry, cmd_flags, path); 772 /* implement the bltin and command builtins here */ 773 if (cmdentry.cmdtype != CMDBUILTIN) 774 break; 775 if (cmdentry.u.index == BLTINCMD) { 776 if (argc == 1) 777 break; 778 argv++; 779 argc--; 780 bltinonly = 1; 781 } else if (cmdentry.u.index == COMMANDCMD) { 782 if (argc == 1) 783 break; 784 if (!strcmp(argv[1], "-p")) { 785 if (argc == 2) 786 break; 787 if (argv[2][0] == '-') { 788 if (strcmp(argv[2], "--")) 789 break; 790 if (argc == 3) 791 break; 792 argv += 3; 793 argc -= 3; 794 } else { 795 argv += 2; 796 argc -= 2; 797 } 798 path = _PATH_STDPATH; 799 clearcmdentry(0); 800 do_clearcmdentry = 1; 801 } else if (!strcmp(argv[1], "--")) { 802 if (argc == 2) 803 break; 804 argv += 2; 805 argc -= 2; 806 } else if (argv[1][0] == '-') 807 break; 808 else { 809 argv++; 810 argc--; 811 } 812 cmd_flags |= DO_NOFUNC; 813 bltinonly = 0; 814 } else 815 break; 816 } 817 /* 818 * Special builtins lose their special properties when 819 * called via 'command'. 820 */ 821 if (cmd_flags & DO_NOFUNC) 822 cmdentry.special = 0; 823 } 824 825 /* Fork off a child process if necessary. */ 826 if (cmd->ncmd.backgnd 827 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) 828 && ((flags & EV_EXIT) == 0 || have_traps())) 829 || ((flags & EV_BACKCMD) != 0 830 && (cmdentry.cmdtype != CMDBUILTIN 831 || cmdentry.u.index == CDCMD 832 || cmdentry.u.index == DOTCMD 833 || cmdentry.u.index == EVALCMD))) { 834 jp = makejob(cmd, 1); 835 mode = cmd->ncmd.backgnd; 836 if (flags & EV_BACKCMD) { 837 mode = FORK_NOJOB; 838 if (pipe(pip) < 0) 839 error("Pipe call failed: %s", strerror(errno)); 840 } 841 if (forkshell(jp, cmd, mode) != 0) 842 goto parent; /* at end of routine */ 843 if (flags & EV_BACKCMD) { 844 FORCEINTON; 845 close(pip[0]); 846 if (pip[1] != 1) { 847 dup2(pip[1], 1); 848 close(pip[1]); 849 } 850 } 851 flags |= EV_EXIT; 852 } 853 854 /* This is the child process if a fork occurred. */ 855 /* Execute the command. */ 856 if (cmdentry.cmdtype == CMDFUNCTION) { 857 #ifdef DEBUG 858 trputs("Shell function: "); trargs(argv); 859 #endif 860 saveparam = shellparam; 861 shellparam.malloc = 0; 862 shellparam.reset = 1; 863 shellparam.nparam = argc - 1; 864 shellparam.p = argv + 1; 865 shellparam.optnext = NULL; 866 INTOFF; 867 savelocalvars = localvars; 868 localvars = NULL; 869 reffunc(cmdentry.u.func); 870 savehandler = handler; 871 if (setjmp(jmploc.loc)) { 872 if (exception == EXSHELLPROC) 873 freeparam(&saveparam); 874 else { 875 freeparam(&shellparam); 876 shellparam = saveparam; 877 if (exception == EXERROR || exception == EXEXEC) 878 popredir(); 879 } 880 unreffunc(cmdentry.u.func); 881 poplocalvars(); 882 localvars = savelocalvars; 883 funcnest--; 884 handler = savehandler; 885 longjmp(handler->loc, 1); 886 } 887 handler = &jmploc; 888 funcnest++; 889 redirect(cmd->ncmd.redirect, REDIR_PUSH); 890 INTON; 891 for (sp = varlist.list ; sp ; sp = sp->next) 892 mklocal(sp->text); 893 exitstatus = oexitstatus; 894 if (flags & EV_TESTED) 895 evaltree(getfuncnode(cmdentry.u.func), EV_TESTED); 896 else 897 evaltree(getfuncnode(cmdentry.u.func), 0); 898 INTOFF; 899 unreffunc(cmdentry.u.func); 900 poplocalvars(); 901 localvars = savelocalvars; 902 freeparam(&shellparam); 903 shellparam = saveparam; 904 handler = savehandler; 905 funcnest--; 906 popredir(); 907 INTON; 908 if (evalskip == SKIPFUNC) { 909 evalskip = 0; 910 skipcount = 0; 911 } 912 if (flags & EV_EXIT) 913 exitshell(exitstatus); 914 } else if (cmdentry.cmdtype == CMDBUILTIN) { 915 #ifdef DEBUG 916 trputs("builtin command: "); trargs(argv); 917 #endif 918 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 919 if (flags == EV_BACKCMD) { 920 memout.nleft = 0; 921 memout.nextc = memout.buf; 922 memout.bufsize = 64; 923 mode |= REDIR_BACKQ; 924 cmdentry.special = 0; 925 } 926 savecmdname = commandname; 927 savetopfile = getcurrentfile(); 928 cmdenviron = varlist.list; 929 e = -1; 930 savehandler = handler; 931 if (setjmp(jmploc.loc)) { 932 e = exception; 933 exitstatus = (e == EXINT)? SIGINT+128 : 2; 934 goto cmddone; 935 } 936 handler = &jmploc; 937 redirect(cmd->ncmd.redirect, mode); 938 /* 939 * If there is no command word, redirection errors should 940 * not be fatal but assignment errors should. 941 */ 942 if (argc == 0 && !(flags & EV_BACKCMD)) 943 cmdentry.special = 1; 944 if (cmdentry.special) 945 listsetvar(cmdenviron); 946 if (argc > 0) 947 bltinsetlocale(); 948 commandname = argv[0]; 949 argptr = argv + 1; 950 nextopt_optptr = NULL; /* initialize nextopt */ 951 builtin_flags = flags; 952 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 953 flushall(); 954 cmddone: 955 if (argc > 0) 956 bltinunsetlocale(); 957 cmdenviron = NULL; 958 out1 = &output; 959 out2 = &errout; 960 freestdout(); 961 if (e != EXSHELLPROC) { 962 commandname = savecmdname; 963 if (flags & EV_EXIT) { 964 exitshell(exitstatus); 965 } 966 } 967 handler = savehandler; 968 if (flags == EV_BACKCMD) { 969 backcmd->buf = memout.buf; 970 backcmd->nleft = memout.nextc - memout.buf; 971 memout.buf = NULL; 972 } 973 if (cmdentry.u.index != EXECCMD && 974 (e == -1 || e == EXERROR || e == EXEXEC)) 975 popredir(); 976 if (e != -1) { 977 if ((e != EXERROR && e != EXEXEC) 978 || cmdentry.special) 979 exraise(e); 980 popfilesupto(savetopfile); 981 if (flags != EV_BACKCMD) 982 FORCEINTON; 983 } 984 } else { 985 #ifdef DEBUG 986 trputs("normal command: "); trargs(argv); 987 #endif 988 redirect(cmd->ncmd.redirect, 0); 989 for (sp = varlist.list ; sp ; sp = sp->next) 990 setvareq(sp->text, VEXPORT|VSTACK); 991 envp = environment(); 992 shellexec(argv, envp, path, cmdentry.u.index); 993 /*NOTREACHED*/ 994 } 995 goto out; 996 997 parent: /* parent process gets here (if we forked) */ 998 if (mode == 0) { /* argument to fork */ 999 INTOFF; 1000 exitstatus = waitforjob(jp, &realstatus); 1001 INTON; 1002 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 1003 evalskip = SKIPBREAK; 1004 skipcount = loopnest; 1005 } 1006 } else if (mode == 2) { 1007 backcmd->fd = pip[0]; 1008 close(pip[1]); 1009 backcmd->jp = jp; 1010 } 1011 1012 out: 1013 if (lastarg) 1014 setvar("_", lastarg, 0); 1015 if (do_clearcmdentry) 1016 clearcmdentry(0); 1017 popstackmark(&smark); 1018 } 1019 1020 1021 1022 /* 1023 * Search for a command. This is called before we fork so that the 1024 * location of the command will be available in the parent as well as 1025 * the child. The check for "goodname" is an overly conservative 1026 * check that the name will not be subject to expansion. 1027 */ 1028 1029 STATIC void 1030 prehash(union node *n) 1031 { 1032 struct cmdentry entry; 1033 1034 if (n && n->type == NCMD && n->ncmd.args) 1035 if (goodname(n->ncmd.args->narg.text)) 1036 find_command(n->ncmd.args->narg.text, &entry, 0, 1037 pathval()); 1038 } 1039 1040 1041 1042 /* 1043 * Builtin commands. Builtin commands whose functions are closely 1044 * tied to evaluation are implemented here. 1045 */ 1046 1047 /* 1048 * No command given, a bltin command with no arguments, or a bltin command 1049 * with an invalid name. 1050 */ 1051 1052 int 1053 bltincmd(int argc, char **argv) 1054 { 1055 if (argc > 1) { 1056 out2fmt_flush("%s: not found\n", argv[1]); 1057 return 127; 1058 } 1059 /* 1060 * Preserve exitstatus of a previous possible redirection 1061 * as POSIX mandates 1062 */ 1063 return exitstatus; 1064 } 1065 1066 1067 /* 1068 * Handle break and continue commands. Break, continue, and return are 1069 * all handled by setting the evalskip flag. The evaluation routines 1070 * above all check this flag, and if it is set they start skipping 1071 * commands rather than executing them. The variable skipcount is 1072 * the number of loops to break/continue, or the number of function 1073 * levels to return. (The latter is always 1.) It should probably 1074 * be an error to break out of more loops than exist, but it isn't 1075 * in the standard shell so we don't make it one here. 1076 */ 1077 1078 int 1079 breakcmd(int argc, char **argv) 1080 { 1081 int n = argc > 1 ? number(argv[1]) : 1; 1082 1083 if (n > loopnest) 1084 n = loopnest; 1085 if (n > 0) { 1086 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1087 skipcount = n; 1088 } 1089 return 0; 1090 } 1091 1092 /* 1093 * The `command' command. 1094 */ 1095 int 1096 commandcmd(int argc, char **argv) 1097 { 1098 const char *path; 1099 int ch; 1100 int cmd = -1; 1101 1102 path = bltinlookup("PATH", 1); 1103 1104 optind = optreset = 1; 1105 opterr = 0; 1106 while ((ch = getopt(argc, argv, "pvV")) != -1) { 1107 switch (ch) { 1108 case 'p': 1109 path = _PATH_STDPATH; 1110 break; 1111 case 'v': 1112 cmd = TYPECMD_SMALLV; 1113 break; 1114 case 'V': 1115 cmd = TYPECMD_BIGV; 1116 break; 1117 case '?': 1118 default: 1119 error("unknown option: -%c", optopt); 1120 } 1121 } 1122 argc -= optind; 1123 argv += optind; 1124 1125 if (cmd != -1) { 1126 if (argc != 1) 1127 error("wrong number of arguments"); 1128 return typecmd_impl(2, argv - 1, cmd, path); 1129 } 1130 if (argc != 0) 1131 error("commandcmd() called while it should not be"); 1132 1133 /* 1134 * Do nothing successfully if no command was specified; 1135 * ksh also does this. 1136 */ 1137 return 0; 1138 } 1139 1140 1141 /* 1142 * The return command. 1143 */ 1144 1145 int 1146 returncmd(int argc, char **argv) 1147 { 1148 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 1149 1150 if (funcnest) { 1151 evalskip = SKIPFUNC; 1152 skipcount = 1; 1153 } else { 1154 /* skip the rest of the file */ 1155 evalskip = SKIPFILE; 1156 skipcount = 1; 1157 } 1158 return ret; 1159 } 1160 1161 1162 int 1163 falsecmd(int argc __unused, char **argv __unused) 1164 { 1165 return 1; 1166 } 1167 1168 1169 int 1170 truecmd(int argc __unused, char **argv __unused) 1171 { 1172 return 0; 1173 } 1174 1175 1176 int 1177 execcmd(int argc, char **argv) 1178 { 1179 /* 1180 * Because we have historically not supported any options, 1181 * only treat "--" specially. 1182 */ 1183 if (argc > 1 && strcmp(argv[1], "--") == 0) 1184 argc--, argv++; 1185 if (argc > 1) { 1186 struct strlist *sp; 1187 1188 iflag = 0; /* exit on error */ 1189 mflag = 0; 1190 optschanged(); 1191 for (sp = cmdenviron; sp ; sp = sp->next) 1192 setvareq(sp->text, VEXPORT|VSTACK); 1193 shellexec(argv + 1, environment(), pathval(), 0); 1194 1195 } 1196 return 0; 1197 } 1198 1199 1200 int 1201 timescmd(int argc __unused, char **argv __unused) 1202 { 1203 struct rusage ru; 1204 long shumins, shsmins, chumins, chsmins; 1205 double shusecs, shssecs, chusecs, chssecs; 1206 1207 if (getrusage(RUSAGE_SELF, &ru) < 0) 1208 return 1; 1209 shumins = ru.ru_utime.tv_sec / 60; 1210 shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1211 shsmins = ru.ru_stime.tv_sec / 60; 1212 shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1213 if (getrusage(RUSAGE_CHILDREN, &ru) < 0) 1214 return 1; 1215 chumins = ru.ru_utime.tv_sec / 60; 1216 chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1217 chsmins = ru.ru_stime.tv_sec / 60; 1218 chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1219 out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins, 1220 shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs); 1221 return 0; 1222 } 1223