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