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