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