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