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 if (argc > 0) 941 bltinsetlocale(); 942 commandname = argv[0]; 943 argptr = argv + 1; 944 nextopt_optptr = NULL; /* initialize nextopt */ 945 builtin_flags = flags; 946 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 947 flushall(); 948 cmddone: 949 if (argc > 0) 950 bltinunsetlocale(); 951 cmdenviron = NULL; 952 out1 = &output; 953 out2 = &errout; 954 freestdout(); 955 if (e != EXSHELLPROC) { 956 commandname = savecmdname; 957 if (flags & EV_EXIT) { 958 exitshell(exitstatus); 959 } 960 } 961 handler = savehandler; 962 if (flags == EV_BACKCMD) { 963 backcmd->buf = memout.buf; 964 backcmd->nleft = memout.nextc - memout.buf; 965 memout.buf = NULL; 966 } 967 if (cmdentry.u.index != EXECCMD && 968 (e == -1 || e == EXERROR || e == EXEXEC)) 969 popredir(); 970 if (e != -1) { 971 if ((e != EXERROR && e != EXEXEC) 972 || cmdentry.special) 973 exraise(e); 974 popfilesupto(savetopfile); 975 if (flags != EV_BACKCMD) 976 FORCEINTON; 977 } 978 } else { 979 #ifdef DEBUG 980 trputs("normal command: "); trargs(argv); 981 #endif 982 redirect(cmd->ncmd.redirect, 0); 983 for (sp = varlist.list ; sp ; sp = sp->next) 984 setvareq(sp->text, VEXPORT|VSTACK); 985 envp = environment(); 986 shellexec(argv, envp, path, cmdentry.u.index); 987 /*NOTREACHED*/ 988 } 989 goto out; 990 991 parent: /* parent process gets here (if we forked) */ 992 if (mode == 0) { /* argument to fork */ 993 INTOFF; 994 exitstatus = waitforjob(jp, &realstatus); 995 INTON; 996 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 997 evalskip = SKIPBREAK; 998 skipcount = loopnest; 999 } 1000 } else if (mode == 2) { 1001 backcmd->fd = pip[0]; 1002 close(pip[1]); 1003 backcmd->jp = jp; 1004 } 1005 1006 out: 1007 if (lastarg) 1008 setvar("_", lastarg, 0); 1009 if (do_clearcmdentry) 1010 clearcmdentry(0); 1011 popstackmark(&smark); 1012 } 1013 1014 1015 1016 /* 1017 * Search for a command. This is called before we fork so that the 1018 * location of the command will be available in the parent as well as 1019 * the child. The check for "goodname" is an overly conservative 1020 * check that the name will not be subject to expansion. 1021 */ 1022 1023 STATIC void 1024 prehash(union node *n) 1025 { 1026 struct cmdentry entry; 1027 1028 if (n && n->type == NCMD && n->ncmd.args) 1029 if (goodname(n->ncmd.args->narg.text)) 1030 find_command(n->ncmd.args->narg.text, &entry, 0, 1031 pathval()); 1032 } 1033 1034 1035 1036 /* 1037 * Builtin commands. Builtin commands whose functions are closely 1038 * tied to evaluation are implemented here. 1039 */ 1040 1041 /* 1042 * No command given, a bltin command with no arguments, or a bltin command 1043 * with an invalid name. 1044 */ 1045 1046 int 1047 bltincmd(int argc, char **argv) 1048 { 1049 if (argc > 1) { 1050 out2fmt_flush("%s: not found\n", argv[1]); 1051 return 127; 1052 } 1053 /* 1054 * Preserve exitstatus of a previous possible redirection 1055 * as POSIX mandates 1056 */ 1057 return exitstatus; 1058 } 1059 1060 1061 /* 1062 * Handle break and continue commands. Break, continue, and return are 1063 * all handled by setting the evalskip flag. The evaluation routines 1064 * above all check this flag, and if it is set they start skipping 1065 * commands rather than executing them. The variable skipcount is 1066 * the number of loops to break/continue, or the number of function 1067 * levels to return. (The latter is always 1.) It should probably 1068 * be an error to break out of more loops than exist, but it isn't 1069 * in the standard shell so we don't make it one here. 1070 */ 1071 1072 int 1073 breakcmd(int argc, char **argv) 1074 { 1075 int n = argc > 1 ? number(argv[1]) : 1; 1076 1077 if (n > loopnest) 1078 n = loopnest; 1079 if (n > 0) { 1080 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1081 skipcount = n; 1082 } 1083 return 0; 1084 } 1085 1086 /* 1087 * The `command' command. 1088 */ 1089 int 1090 commandcmd(int argc, char **argv) 1091 { 1092 const char *path; 1093 int ch; 1094 int cmd = -1; 1095 1096 path = bltinlookup("PATH", 1); 1097 1098 optind = optreset = 1; 1099 opterr = 0; 1100 while ((ch = getopt(argc, argv, "pvV")) != -1) { 1101 switch (ch) { 1102 case 'p': 1103 path = _PATH_STDPATH; 1104 break; 1105 case 'v': 1106 cmd = TYPECMD_SMALLV; 1107 break; 1108 case 'V': 1109 cmd = TYPECMD_BIGV; 1110 break; 1111 case '?': 1112 default: 1113 error("unknown option: -%c", optopt); 1114 } 1115 } 1116 argc -= optind; 1117 argv += optind; 1118 1119 if (cmd != -1) { 1120 if (argc != 1) 1121 error("wrong number of arguments"); 1122 return typecmd_impl(2, argv - 1, cmd, path); 1123 } 1124 if (argc != 0) 1125 error("commandcmd() called while it should not be"); 1126 1127 /* 1128 * Do nothing successfully if no command was specified; 1129 * ksh also does this. 1130 */ 1131 return 0; 1132 } 1133 1134 1135 /* 1136 * The return command. 1137 */ 1138 1139 int 1140 returncmd(int argc, char **argv) 1141 { 1142 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 1143 1144 if (funcnest) { 1145 evalskip = SKIPFUNC; 1146 skipcount = 1; 1147 } else { 1148 /* skip the rest of the file */ 1149 evalskip = SKIPFILE; 1150 skipcount = 1; 1151 } 1152 return ret; 1153 } 1154 1155 1156 int 1157 falsecmd(int argc __unused, char **argv __unused) 1158 { 1159 return 1; 1160 } 1161 1162 1163 int 1164 truecmd(int argc __unused, char **argv __unused) 1165 { 1166 return 0; 1167 } 1168 1169 1170 int 1171 execcmd(int argc, char **argv) 1172 { 1173 /* 1174 * Because we have historically not supported any options, 1175 * only treat "--" specially. 1176 */ 1177 if (argc > 1 && strcmp(argv[1], "--") == 0) 1178 argc--, argv++; 1179 if (argc > 1) { 1180 struct strlist *sp; 1181 1182 iflag = 0; /* exit on error */ 1183 mflag = 0; 1184 optschanged(); 1185 for (sp = cmdenviron; sp ; sp = sp->next) 1186 setvareq(sp->text, VEXPORT|VSTACK); 1187 shellexec(argv + 1, environment(), pathval(), 0); 1188 1189 } 1190 return 0; 1191 } 1192 1193 1194 int 1195 timescmd(int argc __unused, char **argv __unused) 1196 { 1197 struct rusage ru; 1198 long shumins, shsmins, chumins, chsmins; 1199 double shusecs, shssecs, chusecs, chssecs; 1200 1201 if (getrusage(RUSAGE_SELF, &ru) < 0) 1202 return 1; 1203 shumins = ru.ru_utime.tv_sec / 60; 1204 shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1205 shsmins = ru.ru_stime.tv_sec / 60; 1206 shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1207 if (getrusage(RUSAGE_CHILDREN, &ru) < 0) 1208 return 1; 1209 chumins = ru.ru_utime.tv_sec / 60; 1210 chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1211 chsmins = ru.ru_stime.tv_sec / 60; 1212 chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1213 out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins, 1214 shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs); 1215 return 0; 1216 } 1217