1 /* $NetBSD: eval.c,v 1.69 2002/11/25 21:55:58 agc Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 43 #else 44 __RCSID("$NetBSD: eval.c,v 1.69 2002/11/25 21:55:58 agc Exp $"); 45 #endif 46 #endif /* not lint */ 47 48 #include <signal.h> 49 #include <stdio.h> 50 #include <unistd.h> 51 #include <sys/times.h> 52 53 #include <sys/types.h> 54 #include <sys/wait.h> 55 56 /* 57 * Evaluate a command. 58 */ 59 60 #include "shell.h" 61 #include "nodes.h" 62 #include "syntax.h" 63 #include "expand.h" 64 #include "parser.h" 65 #include "jobs.h" 66 #include "eval.h" 67 #include "builtins.h" 68 #include "options.h" 69 #include "exec.h" 70 #include "redir.h" 71 #include "input.h" 72 #include "output.h" 73 #include "trap.h" 74 #include "var.h" 75 #include "memalloc.h" 76 #include "error.h" 77 #include "show.h" 78 #include "mystring.h" 79 #include "main.h" 80 #ifndef SMALL 81 #include "myhistedit.h" 82 #endif 83 84 85 /* flags in argument to evaltree */ 86 #define EV_EXIT 01 /* exit after evaluating tree */ 87 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 88 #define EV_BACKCMD 04 /* command executing within back quotes */ 89 90 int evalskip; /* set if we are skipping commands */ 91 STATIC int skipcount; /* number of levels to skip */ 92 MKINIT int loopnest; /* current loop nesting level */ 93 int funcnest; /* depth of function calls */ 94 95 96 char *commandname; 97 struct strlist *cmdenviron; 98 int exitstatus; /* exit status of last command */ 99 int back_exitstatus; /* exit status of backquoted command */ 100 101 102 STATIC void evalloop(union node *, int); 103 STATIC void evalfor(union node *, int); 104 STATIC void evalcase(union node *, int); 105 STATIC void evalsubshell(union node *, int); 106 STATIC void expredir(union node *); 107 STATIC void evalpipe(union node *); 108 STATIC void evalcommand(union node *, int, struct backcmd *); 109 STATIC void prehash(union node *); 110 111 112 /* 113 * Called to reset things after an exception. 114 */ 115 116 #ifdef mkinit 117 INCLUDE "eval.h" 118 119 RESET { 120 evalskip = 0; 121 loopnest = 0; 122 funcnest = 0; 123 } 124 125 SHELLPROC { 126 exitstatus = 0; 127 } 128 #endif 129 130 131 132 /* 133 * The eval commmand. 134 */ 135 136 int 137 evalcmd(int argc, char **argv) 138 { 139 char *p; 140 char *concat; 141 char **ap; 142 143 if (argc > 1) { 144 p = argv[1]; 145 if (argc > 2) { 146 STARTSTACKSTR(concat); 147 ap = argv + 2; 148 for (;;) { 149 while (*p) 150 STPUTC(*p++, concat); 151 if ((p = *ap++) == NULL) 152 break; 153 STPUTC(' ', concat); 154 } 155 STPUTC('\0', concat); 156 p = grabstackstr(concat); 157 } 158 evalstring(p, EV_TESTED); 159 } 160 return exitstatus; 161 } 162 163 164 /* 165 * Execute a command or commands contained in a string. 166 */ 167 168 void 169 evalstring(char *s, int flag) 170 { 171 union node *n; 172 struct stackmark smark; 173 174 setstackmark(&smark); 175 setinputstring(s, 1); 176 177 while ((n = parsecmd(0)) != NEOF) { 178 evaltree(n, flag); 179 popstackmark(&smark); 180 } 181 popfile(); 182 popstackmark(&smark); 183 } 184 185 186 187 /* 188 * Evaluate a parse tree. The value is left in the global variable 189 * exitstatus. 190 */ 191 192 void 193 evaltree(union node *n, int flags) 194 { 195 if (n == NULL) { 196 TRACE(("evaltree(NULL) called\n")); 197 exitstatus = 0; 198 goto out; 199 } 200 #ifndef SMALL 201 displayhist = 1; /* show history substitutions done with fc */ 202 #endif 203 TRACE(("pid %d, evaltree(%p: %d) called\n", getpid(), n, n->type)); 204 switch (n->type) { 205 case NSEMI: 206 evaltree(n->nbinary.ch1, flags & EV_TESTED); 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 /* don't bomb out on "set -e; false && true" */ 215 flags |= EV_TESTED; 216 goto out; 217 } 218 evaltree(n->nbinary.ch2, flags | EV_TESTED); 219 break; 220 case NOR: 221 evaltree(n->nbinary.ch1, EV_TESTED); 222 if (evalskip || exitstatus == 0) 223 goto out; 224 evaltree(n->nbinary.ch2, flags | EV_TESTED); 225 break; 226 case NREDIR: 227 expredir(n->nredir.redirect); 228 redirect(n->nredir.redirect, REDIR_PUSH); 229 evaltree(n->nredir.n, flags); 230 popredir(); 231 break; 232 case NSUBSHELL: 233 evalsubshell(n, flags); 234 break; 235 case NBACKGND: 236 evalsubshell(n, flags); 237 break; 238 case NIF: { 239 evaltree(n->nif.test, EV_TESTED); 240 if (evalskip) 241 goto out; 242 if (exitstatus == 0) 243 evaltree(n->nif.ifpart, flags); 244 else if (n->nif.elsepart) 245 evaltree(n->nif.elsepart, flags); 246 else 247 exitstatus = 0; 248 break; 249 } 250 case NWHILE: 251 case NUNTIL: 252 evalloop(n, flags); 253 break; 254 case NFOR: 255 evalfor(n, flags); 256 break; 257 case NCASE: 258 evalcase(n, flags); 259 break; 260 case NDEFUN: 261 defun(n->narg.text, n->narg.next); 262 exitstatus = 0; 263 break; 264 case NNOT: 265 evaltree(n->nnot.com, EV_TESTED); 266 exitstatus = !exitstatus; 267 break; 268 269 case NPIPE: 270 evalpipe(n); 271 break; 272 case NCMD: 273 evalcommand(n, flags, (struct backcmd *)NULL); 274 break; 275 default: 276 out1fmt("Node type = %d\n", n->type); 277 flushout(&output); 278 break; 279 } 280 out: 281 if (pendingsigs) 282 dotrap(); 283 if ((flags & EV_EXIT) != 0) 284 exitshell(exitstatus); 285 } 286 287 288 STATIC void 289 evalloop(union node *n, int flags) 290 { 291 int status; 292 293 loopnest++; 294 status = 0; 295 for (;;) { 296 evaltree(n->nbinary.ch1, EV_TESTED); 297 if (evalskip) { 298 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 299 evalskip = 0; 300 continue; 301 } 302 if (evalskip == SKIPBREAK && --skipcount <= 0) 303 evalskip = 0; 304 break; 305 } 306 if (n->type == NWHILE) { 307 if (exitstatus != 0) 308 break; 309 } else { 310 if (exitstatus == 0) 311 break; 312 } 313 evaltree(n->nbinary.ch2, flags & EV_TESTED); 314 status = exitstatus; 315 if (evalskip) 316 goto skipping; 317 } 318 loopnest--; 319 exitstatus = status; 320 } 321 322 323 324 STATIC void 325 evalfor(union node *n, int flags) 326 { 327 struct arglist arglist; 328 union node *argp; 329 struct strlist *sp; 330 struct stackmark smark; 331 int status = 0; 332 333 setstackmark(&smark); 334 arglist.lastp = &arglist.list; 335 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 336 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 337 if (evalskip) 338 goto out; 339 } 340 *arglist.lastp = NULL; 341 342 loopnest++; 343 for (sp = arglist.list ; sp ; sp = sp->next) { 344 setvar(n->nfor.var, sp->text, 0); 345 evaltree(n->nfor.body, flags & EV_TESTED); 346 status = exitstatus; 347 if (evalskip) { 348 if (evalskip == SKIPCONT && --skipcount <= 0) { 349 evalskip = 0; 350 continue; 351 } 352 if (evalskip == SKIPBREAK && --skipcount <= 0) 353 evalskip = 0; 354 break; 355 } 356 } 357 loopnest--; 358 exitstatus = status; 359 out: 360 popstackmark(&smark); 361 } 362 363 364 365 STATIC void 366 evalcase(union node *n, int flags) 367 { 368 union node *cp; 369 union node *patp; 370 struct arglist arglist; 371 struct stackmark smark; 372 int status = 0; 373 374 setstackmark(&smark); 375 arglist.lastp = &arglist.list; 376 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 377 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 378 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 379 if (casematch(patp, arglist.list->text)) { 380 if (evalskip == 0) { 381 evaltree(cp->nclist.body, flags); 382 status = exitstatus; 383 } 384 goto out; 385 } 386 } 387 } 388 out: 389 exitstatus = status; 390 popstackmark(&smark); 391 } 392 393 394 395 /* 396 * Kick off a subshell to evaluate a tree. 397 */ 398 399 STATIC void 400 evalsubshell(union node *n, int flags) 401 { 402 struct job *jp; 403 int backgnd = (n->type == NBACKGND); 404 405 expredir(n->nredir.redirect); 406 INTOFF; 407 jp = makejob(n, 1); 408 if (forkshell(jp, n, backgnd) == 0) { 409 INTON; 410 if (backgnd) 411 flags &=~ EV_TESTED; 412 redirect(n->nredir.redirect, 0); 413 /* never returns */ 414 evaltree(n->nredir.n, flags | EV_EXIT); 415 } 416 if (! backgnd) 417 exitstatus = waitforjob(jp); 418 INTON; 419 } 420 421 422 423 /* 424 * Compute the names of the files in a redirection list. 425 */ 426 427 STATIC void 428 expredir(union node *n) 429 { 430 union node *redir; 431 432 for (redir = n ; redir ; redir = redir->nfile.next) { 433 struct arglist fn; 434 fn.lastp = &fn.list; 435 switch (redir->type) { 436 case NFROMTO: 437 case NFROM: 438 case NTO: 439 case NCLOBBER: 440 case NAPPEND: 441 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 442 redir->nfile.expfname = fn.list->text; 443 break; 444 case NFROMFD: 445 case NTOFD: 446 if (redir->ndup.vname) { 447 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 448 fixredir(redir, fn.list->text, 1); 449 } 450 break; 451 } 452 } 453 } 454 455 456 457 /* 458 * Evaluate a pipeline. All the processes in the pipeline are children 459 * of the process creating the pipeline. (This differs from some versions 460 * of the shell, which make the last process in a pipeline the parent 461 * of all the rest.) 462 */ 463 464 STATIC void 465 evalpipe(union node *n) 466 { 467 struct job *jp; 468 struct nodelist *lp; 469 int pipelen; 470 int prevfd; 471 int pip[2]; 472 473 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 474 pipelen = 0; 475 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 476 pipelen++; 477 INTOFF; 478 jp = makejob(n, pipelen); 479 prevfd = -1; 480 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 481 prehash(lp->n); 482 pip[1] = -1; 483 if (lp->next) { 484 if (pipe(pip) < 0) { 485 close(prevfd); 486 error("Pipe call failed"); 487 } 488 } 489 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 490 INTON; 491 if (prevfd > 0) { 492 close(0); 493 copyfd(prevfd, 0); 494 close(prevfd); 495 } 496 if (pip[1] >= 0) { 497 close(pip[0]); 498 if (pip[1] != 1) { 499 close(1); 500 copyfd(pip[1], 1); 501 close(pip[1]); 502 } 503 } 504 evaltree(lp->n, EV_EXIT); 505 } 506 if (prevfd >= 0) 507 close(prevfd); 508 prevfd = pip[0]; 509 close(pip[1]); 510 } 511 if (n->npipe.backgnd == 0) { 512 exitstatus = waitforjob(jp); 513 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 514 } 515 INTON; 516 } 517 518 519 520 /* 521 * Execute a command inside back quotes. If it's a builtin command, we 522 * want to save its output in a block obtained from malloc. Otherwise 523 * we fork off a subprocess and get the output of the command via a pipe. 524 * Should be called with interrupts off. 525 */ 526 527 void 528 evalbackcmd(union node *n, struct backcmd *result) 529 { 530 int pip[2]; 531 struct job *jp; 532 struct stackmark smark; /* unnecessary */ 533 534 setstackmark(&smark); 535 result->fd = -1; 536 result->buf = NULL; 537 result->nleft = 0; 538 result->jp = NULL; 539 if (n == NULL) { 540 goto out; 541 } 542 #ifdef notyet 543 /* 544 * For now we disable executing builtins in the same 545 * context as the shell, because we are not keeping 546 * enough state to recover from changes that are 547 * supposed only to affect subshells. eg. echo "`cd /`" 548 */ 549 if (n->type == NCMD) { 550 exitstatus = oexitstatus; 551 evalcommand(n, EV_BACKCMD, result); 552 } else 553 #endif 554 { 555 INTOFF; 556 if (pipe(pip) < 0) 557 error("Pipe call failed"); 558 jp = makejob(n, 1); 559 if (forkshell(jp, n, FORK_NOJOB) == 0) { 560 FORCEINTON; 561 close(pip[0]); 562 if (pip[1] != 1) { 563 close(1); 564 copyfd(pip[1], 1); 565 close(pip[1]); 566 } 567 eflag = 0; 568 evaltree(n, EV_EXIT); 569 /* NOTREACHED */ 570 } 571 close(pip[1]); 572 result->fd = pip[0]; 573 result->jp = jp; 574 INTON; 575 } 576 out: 577 popstackmark(&smark); 578 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 579 result->fd, result->buf, result->nleft, result->jp)); 580 } 581 582 583 int vforked = 0; 584 585 /* 586 * Execute a simple command. 587 */ 588 589 STATIC void 590 evalcommand(union node *cmd, int flags, struct backcmd *backcmd) 591 { 592 struct stackmark smark; 593 union node *argp; 594 struct arglist arglist; 595 struct arglist varlist; 596 char **argv; 597 int argc; 598 char **envp; 599 int varflag; 600 struct strlist *sp; 601 int mode; 602 int pip[2]; 603 struct cmdentry cmdentry; 604 struct job *jp; 605 struct jmploc jmploc; 606 struct jmploc *volatile savehandler; 607 char *volatile savecmdname; 608 volatile struct shparam saveparam; 609 struct localvar *volatile savelocalvars; 610 volatile int e; 611 char *lastarg; 612 #if __GNUC__ 613 /* Avoid longjmp clobbering */ 614 (void) &argv; 615 (void) &argc; 616 (void) &lastarg; 617 (void) &flags; 618 #endif 619 620 vforked = 0; 621 /* First expand the arguments. */ 622 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 623 setstackmark(&smark); 624 back_exitstatus = 0; 625 626 arglist.lastp = &arglist.list; 627 varflag = 1; 628 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 629 char *p = argp->narg.text; 630 if (varflag && is_name(*p)) { 631 do { 632 p++; 633 } while (is_in_name(*p)); 634 if (*p == '=') 635 continue; 636 } 637 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 638 varflag = 0; 639 } 640 *arglist.lastp = NULL; 641 642 expredir(cmd->ncmd.redirect); 643 644 varlist.lastp = &varlist.list; 645 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 646 char *p = argp->narg.text; 647 if (!is_name(*p)) 648 break; 649 do 650 p++; 651 while (is_in_name(*p)); 652 if (*p != '=') 653 break; 654 expandarg(argp, &varlist, EXP_VARTILDE); 655 } 656 *varlist.lastp = NULL; 657 658 argc = 0; 659 for (sp = arglist.list ; sp ; sp = sp->next) 660 argc++; 661 argv = stalloc(sizeof (char *) * (argc + 1)); 662 663 for (sp = arglist.list ; sp ; sp = sp->next) { 664 TRACE(("evalcommand arg: %s\n", sp->text)); 665 *argv++ = sp->text; 666 } 667 *argv = NULL; 668 lastarg = NULL; 669 if (iflag && funcnest == 0 && argc > 0) 670 lastarg = argv[-1]; 671 argv -= argc; 672 673 /* Print the command if xflag is set. */ 674 if (xflag) { 675 outc('+', &errout); 676 for (sp = varlist.list ; sp ; sp = sp->next) { 677 outc(' ', &errout); 678 out2str(sp->text); 679 } 680 for (sp = arglist.list ; sp ; sp = sp->next) { 681 outc(' ', &errout); 682 out2str(sp->text); 683 } 684 outc('\n', &errout); 685 flushout(&errout); 686 } 687 688 /* Now locate the command. */ 689 if (argc == 0) { 690 cmdentry.cmdtype = CMDBUILTIN; 691 cmdentry.u.bltin = bltincmd; 692 } else { 693 static const char PATH[] = "PATH="; 694 const char *path = pathval(); 695 696 /* 697 * Modify the command lookup path, if a PATH= assignment 698 * is present 699 */ 700 for (sp = varlist.list ; sp ; sp = sp->next) 701 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 702 path = sp->text + sizeof(PATH) - 1; 703 704 find_command(argv[0], &cmdentry, DO_ERR, path); 705 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 706 exitstatus = 127; 707 flushout(&errout); 708 return; 709 } 710 /* implement the 'command' (was bltin) builtin here */ 711 while (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.bltin == bltincmd) { 712 argv++; 713 if (--argc == 0) 714 break; 715 if ((cmdentry.u.bltin = find_builtin(*argv)) != 0) 716 continue; 717 if ((cmdentry.u.bltin = find_splbltin(*argv)) == 0) { 718 outfmt(&errout, "%s: not found\n", *argv); 719 exitstatus = 127; 720 flushout(&errout); 721 return; 722 } 723 cmdentry.cmdtype = CMDSPLBLTIN; 724 break; 725 } 726 } 727 728 /* Fork off a child process if necessary. */ 729 if (cmd->ncmd.backgnd 730 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) 731 || ((flags & EV_BACKCMD) != 0 732 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) 733 || cmdentry.u.bltin == dotcmd 734 || cmdentry.u.bltin == evalcmd))) { 735 INTOFF; 736 jp = makejob(cmd, 1); 737 mode = cmd->ncmd.backgnd; 738 if (flags & EV_BACKCMD) { 739 mode = FORK_NOJOB; 740 if (pipe(pip) < 0) 741 error("Pipe call failed"); 742 } 743 #ifdef DO_SHAREDVFORK 744 /* It is essential that if DO_SHAREDVFORK is defined that the 745 * child's address space is actually shared with the parent as 746 * we rely on this. 747 */ 748 if (cmdentry.cmdtype == CMDNORMAL) { 749 pid_t pid; 750 751 savelocalvars = localvars; 752 localvars = NULL; 753 vforked = 1; 754 switch (pid = vfork()) { 755 case -1: 756 TRACE(("Vfork failed, errno=%d", errno)); 757 INTON; 758 error("Cannot vfork"); 759 break; 760 case 0: 761 /* Make sure that exceptions only unwind to 762 * after the vfork(2) 763 */ 764 if (setjmp(jmploc.loc)) { 765 if (exception == EXSHELLPROC) { 766 /* We can't progress with the vfork, 767 * so, set vforked = 2 so the parent 768 * knows, and _exit(); 769 */ 770 vforked = 2; 771 _exit(0); 772 } else { 773 _exit(exerrno); 774 } 775 } 776 savehandler = handler; 777 handler = &jmploc; 778 for (sp = varlist.list; sp; sp = sp->next) 779 mklocal(sp->text, VEXPORT); 780 forkchild(jp, cmd, mode, vforked); 781 break; 782 default: 783 handler = savehandler; /* restore from vfork(2) */ 784 poplocalvars(); 785 localvars = savelocalvars; 786 if (vforked == 2) { 787 vforked = 0; 788 789 (void)waitpid(pid, NULL, 0); 790 /* We need to progress in a normal fork fashion */ 791 goto normal_fork; 792 } 793 vforked = 0; 794 forkparent(jp, cmd, mode, pid); 795 goto parent; 796 } 797 } else { 798 normal_fork: 799 #endif 800 if (forkshell(jp, cmd, mode) != 0) 801 goto parent; /* at end of routine */ 802 FORCEINTON; 803 #ifdef DO_SHAREDVFORK 804 } 805 #endif 806 if (flags & EV_BACKCMD) { 807 if (!vforked) { 808 FORCEINTON; 809 } 810 close(pip[0]); 811 if (pip[1] != 1) { 812 close(1); 813 copyfd(pip[1], 1); 814 close(pip[1]); 815 } 816 } 817 flags |= EV_EXIT; 818 } 819 820 /* This is the child process if a fork occurred. */ 821 /* Execute the command. */ 822 if (cmdentry.cmdtype == CMDFUNCTION) { 823 #ifdef DEBUG 824 trputs("Shell function: "); trargs(argv); 825 #endif 826 redirect(cmd->ncmd.redirect, REDIR_PUSH); 827 saveparam = shellparam; 828 shellparam.malloc = 0; 829 shellparam.reset = 1; 830 shellparam.nparam = argc - 1; 831 shellparam.p = argv + 1; 832 shellparam.optnext = NULL; 833 INTOFF; 834 savelocalvars = localvars; 835 localvars = NULL; 836 INTON; 837 if (setjmp(jmploc.loc)) { 838 if (exception == EXSHELLPROC) { 839 freeparam((volatile struct shparam *) 840 &saveparam); 841 } else { 842 freeparam(&shellparam); 843 shellparam = saveparam; 844 } 845 poplocalvars(); 846 localvars = savelocalvars; 847 handler = savehandler; 848 longjmp(handler->loc, 1); 849 } 850 savehandler = handler; 851 handler = &jmploc; 852 for (sp = varlist.list ; sp ; sp = sp->next) 853 mklocal(sp->text, 0); 854 funcnest++; 855 evaltree(cmdentry.u.func, flags & EV_TESTED); 856 funcnest--; 857 INTOFF; 858 poplocalvars(); 859 localvars = savelocalvars; 860 freeparam(&shellparam); 861 shellparam = saveparam; 862 handler = savehandler; 863 popredir(); 864 INTON; 865 if (evalskip == SKIPFUNC) { 866 evalskip = 0; 867 skipcount = 0; 868 } 869 if (flags & EV_EXIT) 870 exitshell(exitstatus); 871 } else if (cmdentry.cmdtype == CMDBUILTIN || cmdentry.cmdtype == CMDSPLBLTIN) { 872 #ifdef DEBUG 873 trputs("builtin command: "); trargs(argv); 874 #endif 875 mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; 876 if (flags == EV_BACKCMD) { 877 memout.nleft = 0; 878 memout.nextc = memout.buf; 879 memout.bufsize = 64; 880 mode |= REDIR_BACKQ; 881 } 882 savehandler = handler; 883 handler = &jmploc; 884 e = -1; 885 if (!setjmp(jmploc.loc)) { 886 redirect(cmd->ncmd.redirect, mode); 887 888 savecmdname = commandname; 889 /* exec is a special builtin, but needs this list... */ 890 cmdenviron = varlist.list; 891 /* we must check 'readonly' flag for all builtins */ 892 listsetvar(varlist.list, 893 cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); 894 commandname = argv[0]; 895 /* initialize nextopt */ 896 argptr = argv + 1; 897 optptr = NULL; 898 /* and getopt */ 899 optreset = 1; 900 optind = 1; 901 exitstatus = cmdentry.u.bltin(argc, argv); 902 } else { 903 e = exception; 904 exitstatus = e == EXINT ? SIGINT+128 : 905 e == EXEXEC ? exerrno : 2; 906 } 907 flushall(); 908 out1 = &output; 909 out2 = &errout; 910 freestdout(); 911 cmdenviron = NULL; 912 if (e != EXSHELLPROC) { 913 commandname = savecmdname; 914 if (flags & EV_EXIT) 915 exitshell(exitstatus); 916 } 917 handler = savehandler; 918 if (e != -1) { 919 if ((e != EXERROR && e != EXEXEC) 920 || cmdentry.cmdtype == CMDSPLBLTIN 921 || cmdentry.u.bltin == bltincmd) 922 #if 0 923 || cmdentry.u.bltin == dotcmd 924 || cmdentry.u.bltin == evalcmd 925 #ifndef SMALL 926 || cmdentry.u.bltin == histcmd 927 #endif 928 || cmdentry.u.bltin == execcmd) 929 #endif 930 exraise(e); 931 FORCEINTON; 932 } 933 if (cmdentry.u.bltin != execcmd) 934 popredir(); 935 if (flags == EV_BACKCMD) { 936 backcmd->buf = memout.buf; 937 backcmd->nleft = memout.nextc - memout.buf; 938 memout.buf = NULL; 939 } 940 } else { 941 #ifdef DEBUG 942 trputs("normal command: "); trargs(argv); 943 #endif 944 clearredir(vforked); 945 redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0); 946 if (!vforked) 947 for (sp = varlist.list ; sp ; sp = sp->next) 948 setvareq(sp->text, VEXPORT|VSTACK); 949 envp = environment(); 950 shellexec(argv, envp, pathval(), cmdentry.u.index, vforked); 951 } 952 goto out; 953 954 parent: /* parent process gets here (if we forked) */ 955 if (mode == FORK_FG) { /* argument to fork */ 956 exitstatus = waitforjob(jp); 957 } else if (mode == FORK_NOJOB) { 958 backcmd->fd = pip[0]; 959 close(pip[1]); 960 backcmd->jp = jp; 961 } 962 FORCEINTON; 963 964 out: 965 if (lastarg) 966 setvar("_", lastarg, 0); 967 popstackmark(&smark); 968 969 if (eflag && exitstatus && !(flags & EV_TESTED)) 970 exitshell(exitstatus); 971 } 972 973 974 /* 975 * Search for a command. This is called before we fork so that the 976 * location of the command will be available in the parent as well as 977 * the child. The check for "goodname" is an overly conservative 978 * check that the name will not be subject to expansion. 979 */ 980 981 STATIC void 982 prehash(union node *n) 983 { 984 struct cmdentry entry; 985 986 if (n->type == NCMD && n->ncmd.args) 987 if (goodname(n->ncmd.args->narg.text)) 988 find_command(n->ncmd.args->narg.text, &entry, 0, 989 pathval()); 990 } 991 992 993 994 /* 995 * Builtin commands. Builtin commands whose functions are closely 996 * tied to evaluation are implemented here. 997 */ 998 999 /* 1000 * No command given, or a bltin command with no arguments. Set the 1001 * specified variables. 1002 */ 1003 1004 int 1005 bltincmd(int argc, char **argv) 1006 { 1007 /* "command" isn't a special builtin.... */ 1008 listsetvar(cmdenviron, 0); 1009 /* 1010 * Preserve exitstatus of a previous possible redirection 1011 * as POSIX mandates 1012 */ 1013 return back_exitstatus; 1014 } 1015 1016 1017 /* 1018 * Handle break and continue commands. Break, continue, and return are 1019 * all handled by setting the evalskip flag. The evaluation routines 1020 * above all check this flag, and if it is set they start skipping 1021 * commands rather than executing them. The variable skipcount is 1022 * the number of loops to break/continue, or the number of function 1023 * levels to return. (The latter is always 1.) It should probably 1024 * be an error to break out of more loops than exist, but it isn't 1025 * in the standard shell so we don't make it one here. 1026 */ 1027 1028 int 1029 breakcmd(int argc, char **argv) 1030 { 1031 int n = argc > 1 ? number(argv[1]) : 1; 1032 1033 if (n > loopnest) 1034 n = loopnest; 1035 if (n > 0) { 1036 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1037 skipcount = n; 1038 } 1039 return 0; 1040 } 1041 1042 1043 /* 1044 * The return command. 1045 */ 1046 1047 int 1048 returncmd(int argc, char **argv) 1049 { 1050 int ret = argc > 1 ? number(argv[1]) : exitstatus; 1051 1052 if (funcnest) { 1053 evalskip = SKIPFUNC; 1054 skipcount = 1; 1055 return ret; 1056 } 1057 else { 1058 /* Do what ksh does; skip the rest of the file */ 1059 evalskip = SKIPFILE; 1060 skipcount = 1; 1061 return ret; 1062 } 1063 } 1064 1065 1066 int 1067 falsecmd(int argc, char **argv) 1068 { 1069 return 1; 1070 } 1071 1072 1073 int 1074 truecmd(int argc, char **argv) 1075 { 1076 return 0; 1077 } 1078 1079 1080 int 1081 execcmd(int argc, char **argv) 1082 { 1083 if (argc > 1) { 1084 struct strlist *sp; 1085 1086 iflag = 0; /* exit on error */ 1087 mflag = 0; 1088 optschanged(); 1089 for (sp = cmdenviron; sp ; sp = sp->next) 1090 setvareq(sp->text, VEXPORT|VSTACK); 1091 shellexec(argv + 1, environment(), pathval(), 0, 0); 1092 } 1093 return 0; 1094 } 1095 1096 static int 1097 conv_time(clock_t ticks, char *seconds) 1098 { 1099 static clock_t tpm = 0; 1100 clock_t mins; 1101 int i; 1102 1103 if (!tpm) 1104 tpm = sysconf(_SC_CLK_TCK) * 60; 1105 1106 mins = ticks / tpm; 1107 sprintf(seconds, "%.4f", (ticks - mins * tpm) * 60.0 / tpm ); 1108 1109 if (seconds[0] == '6' && seconds[1] == '0') { 1110 /* 59.99995 got rounded up... */ 1111 mins++; 1112 strcpy(seconds, "0.0"); 1113 return mins; 1114 } 1115 1116 /* suppress trailing zeros */ 1117 i = strlen(seconds) - 1; 1118 for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--) 1119 seconds[i] = 0; 1120 return mins; 1121 } 1122 1123 int 1124 timescmd(int argc, char **argv) 1125 { 1126 struct tms tms; 1127 int u, s, cu, cs; 1128 char us[8], ss[8], cus[8], css[8]; 1129 1130 nextopt(""); 1131 1132 times(&tms); 1133 1134 u = conv_time( tms.tms_utime, us ); 1135 s = conv_time( tms.tms_stime, ss ); 1136 cu = conv_time( tms.tms_cutime, cus ); 1137 cs = conv_time( tms.tms_cstime, css ); 1138 1139 outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n", 1140 u, us, s, ss, cu, cus, cs, css); 1141 1142 return 0; 1143 } 1144