1 /* $NetBSD: eval.c,v 1.107 2013/06/27 23:22:04 yamt 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.107 2013/06/27 23:22:04 yamt 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 #if !defined(__minix) 618 static char *sys_path = NULL; 619 static int mib[] = {CTL_USER, USER_CS_PATH}; 620 #endif /* !defined(__minix) */ 621 static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin"; 622 #if !defined(__minix) 623 size_t len; 624 625 if (sys_path == NULL) { 626 if (sysctl(mib, 2, 0, &len, 0, 0) != -1 && 627 (sys_path = ckmalloc(len + 5)) != NULL && 628 sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) { 629 memcpy(sys_path, "PATH=", 5); 630 } else { 631 ckfree(sys_path); 632 /* something to keep things happy */ 633 sys_path = def_path; 634 } 635 } 636 return sys_path; 637 #else 638 /* On Minix no support for CTL_USER. */ 639 return def_path; 640 #endif /* !defined(__minix) */ 641 } 642 643 static int 644 parse_command_args(int argc, char **argv, int *use_syspath) 645 { 646 int sv_argc = argc; 647 char *cp, c; 648 649 *use_syspath = 0; 650 651 for (;;) { 652 argv++; 653 if (--argc == 0) 654 break; 655 cp = *argv; 656 if (*cp++ != '-') 657 break; 658 if (*cp == '-' && cp[1] == 0) { 659 argv++; 660 argc--; 661 break; 662 } 663 while ((c = *cp++)) { 664 switch (c) { 665 case 'p': 666 *use_syspath = 1; 667 break; 668 default: 669 /* run 'typecmd' for other options */ 670 return 0; 671 } 672 } 673 } 674 return sv_argc - argc; 675 } 676 677 int vforked = 0; 678 extern char *trap[]; 679 680 /* 681 * Execute a simple command. 682 */ 683 684 STATIC void 685 evalcommand(union node *cmd, int flgs, struct backcmd *backcmd) 686 { 687 struct stackmark smark; 688 union node *argp; 689 struct arglist arglist; 690 struct arglist varlist; 691 volatile int flags = flgs; 692 char ** volatile argv; 693 volatile int argc; 694 char **envp; 695 int varflag; 696 struct strlist *sp; 697 volatile int mode; 698 int pip[2]; 699 struct cmdentry cmdentry; 700 struct job * volatile jp; 701 struct jmploc jmploc; 702 struct jmploc *volatile savehandler = NULL; 703 const char *volatile savecmdname; 704 volatile struct shparam saveparam; 705 struct localvar *volatile savelocalvars; 706 volatile int e; 707 char * volatile lastarg; 708 const char * volatile path = pathval(); 709 volatile int temp_path; 710 711 vforked = 0; 712 /* First expand the arguments. */ 713 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 714 setstackmark(&smark); 715 back_exitstatus = 0; 716 717 arglist.lastp = &arglist.list; 718 varflag = 1; 719 /* Expand arguments, ignoring the initial 'name=value' ones */ 720 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 721 char *p = argp->narg.text; 722 if (varflag && is_name(*p)) { 723 do { 724 p++; 725 } while (is_in_name(*p)); 726 if (*p == '=') 727 continue; 728 } 729 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 730 varflag = 0; 731 } 732 *arglist.lastp = NULL; 733 734 expredir(cmd->ncmd.redirect); 735 736 /* Now do the initial 'name=value' ones we skipped above */ 737 varlist.lastp = &varlist.list; 738 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 739 char *p = argp->narg.text; 740 if (!is_name(*p)) 741 break; 742 do 743 p++; 744 while (is_in_name(*p)); 745 if (*p != '=') 746 break; 747 expandarg(argp, &varlist, EXP_VARTILDE); 748 } 749 *varlist.lastp = NULL; 750 751 argc = 0; 752 for (sp = arglist.list ; sp ; sp = sp->next) 753 argc++; 754 argv = stalloc(sizeof (char *) * (argc + 1)); 755 756 for (sp = arglist.list ; sp ; sp = sp->next) { 757 TRACE(("evalcommand arg: %s\n", sp->text)); 758 *argv++ = sp->text; 759 } 760 *argv = NULL; 761 lastarg = NULL; 762 if (iflag && funcnest == 0 && argc > 0) 763 lastarg = argv[-1]; 764 argv -= argc; 765 766 /* Print the command if xflag is set. */ 767 if (xflag) { 768 char sep = 0; 769 out2str(ps4val()); 770 for (sp = varlist.list ; sp ; sp = sp->next) { 771 if (sep != 0) 772 outc(sep, &errout); 773 out2shstr(sp->text); 774 sep = ' '; 775 } 776 for (sp = arglist.list ; sp ; sp = sp->next) { 777 if (sep != 0) 778 outc(sep, &errout); 779 out2shstr(sp->text); 780 sep = ' '; 781 } 782 outc('\n', &errout); 783 flushout(&errout); 784 } 785 786 /* Now locate the command. */ 787 if (argc == 0) { 788 cmdentry.cmdtype = CMDSPLBLTIN; 789 cmdentry.u.bltin = bltincmd; 790 } else { 791 static const char PATH[] = "PATH="; 792 int cmd_flags = DO_ERR; 793 794 /* 795 * Modify the command lookup path, if a PATH= assignment 796 * is present 797 */ 798 for (sp = varlist.list; sp; sp = sp->next) 799 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 800 path = sp->text + sizeof(PATH) - 1; 801 802 do { 803 int argsused, use_syspath; 804 find_command(argv[0], &cmdentry, cmd_flags, path); 805 if (cmdentry.cmdtype == CMDUNKNOWN) { 806 exitstatus = 127; 807 flushout(&errout); 808 goto out; 809 } 810 811 /* implement the 'command' builtin here */ 812 if (cmdentry.cmdtype != CMDBUILTIN || 813 cmdentry.u.bltin != bltincmd) 814 break; 815 cmd_flags |= DO_NOFUNC; 816 argsused = parse_command_args(argc, argv, &use_syspath); 817 if (argsused == 0) { 818 /* use 'type' builting to display info */ 819 cmdentry.u.bltin = typecmd; 820 break; 821 } 822 argc -= argsused; 823 argv += argsused; 824 if (use_syspath) 825 path = syspath() + 5; 826 } while (argc != 0); 827 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) 828 /* posix mandates that 'command <splbltin>' act as if 829 <splbltin> was a normal builtin */ 830 cmdentry.cmdtype = CMDBUILTIN; 831 } 832 833 /* Fork off a child process if necessary. */ 834 if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0) 835 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) 836 || ((flags & EV_BACKCMD) != 0 837 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) 838 || cmdentry.u.bltin == dotcmd 839 || cmdentry.u.bltin == evalcmd))) { 840 INTOFF; 841 jp = makejob(cmd, 1); 842 mode = cmd->ncmd.backgnd; 843 if (flags & EV_BACKCMD) { 844 mode = FORK_NOJOB; 845 if (sh_pipe(pip) < 0) 846 error("Pipe call failed"); 847 } 848 #ifdef DO_SHAREDVFORK 849 /* It is essential that if DO_SHAREDVFORK is defined that the 850 * child's address space is actually shared with the parent as 851 * we rely on this. 852 */ 853 if (cmdentry.cmdtype == CMDNORMAL) { 854 pid_t pid; 855 856 savelocalvars = localvars; 857 localvars = NULL; 858 vforked = 1; 859 switch (pid = vfork()) { 860 case -1: 861 TRACE(("Vfork failed, errno=%d\n", errno)); 862 INTON; 863 error("Cannot vfork"); 864 break; 865 case 0: 866 /* Make sure that exceptions only unwind to 867 * after the vfork(2) 868 */ 869 if (setjmp(jmploc.loc)) { 870 if (exception == EXSHELLPROC) { 871 /* We can't progress with the vfork, 872 * so, set vforked = 2 so the parent 873 * knows, and _exit(); 874 */ 875 vforked = 2; 876 _exit(0); 877 } else { 878 _exit(exerrno); 879 } 880 } 881 savehandler = handler; 882 handler = &jmploc; 883 listmklocal(varlist.list, VEXPORT | VNOFUNC); 884 forkchild(jp, cmd, mode, vforked); 885 break; 886 default: 887 handler = savehandler; /* restore from vfork(2) */ 888 poplocalvars(); 889 localvars = savelocalvars; 890 if (vforked == 2) { 891 vforked = 0; 892 893 (void)waitpid(pid, NULL, 0); 894 /* We need to progress in a normal fork fashion */ 895 goto normal_fork; 896 } 897 vforked = 0; 898 forkparent(jp, cmd, mode, pid); 899 goto parent; 900 } 901 } else { 902 normal_fork: 903 #endif 904 if (forkshell(jp, cmd, mode) != 0) 905 goto parent; /* at end of routine */ 906 FORCEINTON; 907 #ifdef DO_SHAREDVFORK 908 } 909 #endif 910 if (flags & EV_BACKCMD) { 911 if (!vforked) { 912 FORCEINTON; 913 } 914 close(pip[0]); 915 if (pip[1] != 1) { 916 close(1); 917 copyfd(pip[1], 1, 1); 918 close(pip[1]); 919 } 920 } 921 flags |= EV_EXIT; 922 } 923 924 /* This is the child process if a fork occurred. */ 925 /* Execute the command. */ 926 switch (cmdentry.cmdtype) { 927 case CMDFUNCTION: 928 #ifdef DEBUG 929 trputs("Shell function: "); trargs(argv); 930 #endif 931 redirect(cmd->ncmd.redirect, REDIR_PUSH); 932 saveparam = shellparam; 933 shellparam.malloc = 0; 934 shellparam.reset = 1; 935 shellparam.nparam = argc - 1; 936 shellparam.p = argv + 1; 937 shellparam.optnext = NULL; 938 INTOFF; 939 savelocalvars = localvars; 940 localvars = NULL; 941 INTON; 942 if (setjmp(jmploc.loc)) { 943 if (exception == EXSHELLPROC) { 944 freeparam((volatile struct shparam *) 945 &saveparam); 946 } else { 947 freeparam(&shellparam); 948 shellparam = saveparam; 949 } 950 poplocalvars(); 951 localvars = savelocalvars; 952 handler = savehandler; 953 longjmp(handler->loc, 1); 954 } 955 savehandler = handler; 956 handler = &jmploc; 957 listmklocal(varlist.list, VEXPORT); 958 /* stop shell blowing its stack */ 959 if (++funcnest > 1000) 960 error("too many nested function calls"); 961 evaltree(cmdentry.u.func, flags & EV_TESTED); 962 funcnest--; 963 INTOFF; 964 poplocalvars(); 965 localvars = savelocalvars; 966 freeparam(&shellparam); 967 shellparam = saveparam; 968 handler = savehandler; 969 popredir(); 970 INTON; 971 if (evalskip == SKIPFUNC) { 972 evalskip = 0; 973 skipcount = 0; 974 } 975 if (flags & EV_EXIT) 976 exitshell(exitstatus); 977 break; 978 979 case CMDBUILTIN: 980 case CMDSPLBLTIN: 981 #ifdef DEBUG 982 trputs("builtin command: "); trargs(argv); 983 #endif 984 mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; 985 if (flags == EV_BACKCMD) { 986 memout.nleft = 0; 987 memout.nextc = memout.buf; 988 memout.bufsize = 64; 989 mode |= REDIR_BACKQ; 990 } 991 e = -1; 992 savehandler = handler; 993 savecmdname = commandname; 994 handler = &jmploc; 995 temp_path = 0; 996 if (!setjmp(jmploc.loc)) { 997 /* We need to ensure the command hash table isn't 998 * corruped by temporary PATH assignments. 999 * However we must ensure the 'local' command works! 1000 */ 1001 if (path != pathval() && (cmdentry.u.bltin == hashcmd || 1002 cmdentry.u.bltin == typecmd)) { 1003 savelocalvars = localvars; 1004 localvars = 0; 1005 temp_path = 1; 1006 mklocal(path - 5 /* PATH= */, 0); 1007 } 1008 redirect(cmd->ncmd.redirect, mode); 1009 1010 /* exec is a special builtin, but needs this list... */ 1011 cmdenviron = varlist.list; 1012 /* we must check 'readonly' flag for all builtins */ 1013 listsetvar(varlist.list, 1014 cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); 1015 commandname = argv[0]; 1016 /* initialize nextopt */ 1017 argptr = argv + 1; 1018 optptr = NULL; 1019 /* and getopt */ 1020 optreset = 1; 1021 optind = 1; 1022 builtin_flags = flags; 1023 exitstatus = cmdentry.u.bltin(argc, argv); 1024 } else { 1025 e = exception; 1026 exitstatus = e == EXINT ? SIGINT + 128 : 1027 e == EXEXEC ? exerrno : 2; 1028 } 1029 handler = savehandler; 1030 flushall(); 1031 out1 = &output; 1032 out2 = &errout; 1033 freestdout(); 1034 if (temp_path) { 1035 poplocalvars(); 1036 localvars = savelocalvars; 1037 } 1038 cmdenviron = NULL; 1039 if (e != EXSHELLPROC) { 1040 commandname = savecmdname; 1041 if (flags & EV_EXIT) 1042 exitshell(exitstatus); 1043 } 1044 if (e != -1) { 1045 if ((e != EXERROR && e != EXEXEC) 1046 || cmdentry.cmdtype == CMDSPLBLTIN) 1047 exraise(e); 1048 FORCEINTON; 1049 } 1050 if (cmdentry.u.bltin != execcmd) 1051 popredir(); 1052 if (flags == EV_BACKCMD) { 1053 backcmd->buf = memout.buf; 1054 backcmd->nleft = memout.nextc - memout.buf; 1055 memout.buf = NULL; 1056 } 1057 break; 1058 1059 default: 1060 #ifdef DEBUG 1061 trputs("normal command: "); trargs(argv); 1062 #endif 1063 redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0); 1064 if (!vforked) 1065 for (sp = varlist.list ; sp ; sp = sp->next) 1066 setvareq(sp->text, VEXPORT|VSTACK); 1067 envp = environment(); 1068 shellexec(argv, envp, path, cmdentry.u.index, vforked); 1069 break; 1070 } 1071 goto out; 1072 1073 parent: /* parent process gets here (if we forked) */ 1074 if (mode == FORK_FG) { /* argument to fork */ 1075 exitstatus = waitforjob(jp); 1076 } else if (mode == FORK_NOJOB) { 1077 backcmd->fd = pip[0]; 1078 close(pip[1]); 1079 backcmd->jp = jp; 1080 } 1081 FORCEINTON; 1082 1083 out: 1084 if (lastarg) 1085 /* dsl: I think this is intended to be used to support 1086 * '_' in 'vi' command mode during line editing... 1087 * However I implemented that within libedit itself. 1088 */ 1089 setvar("_", lastarg, 0); 1090 popstackmark(&smark); 1091 } 1092 1093 1094 /* 1095 * Search for a command. This is called before we fork so that the 1096 * location of the command will be available in the parent as well as 1097 * the child. The check for "goodname" is an overly conservative 1098 * check that the name will not be subject to expansion. 1099 */ 1100 1101 STATIC void 1102 prehash(union node *n) 1103 { 1104 struct cmdentry entry; 1105 1106 if (n && n->type == NCMD && n->ncmd.args) 1107 if (goodname(n->ncmd.args->narg.text)) 1108 find_command(n->ncmd.args->narg.text, &entry, 0, 1109 pathval()); 1110 } 1111 1112 1113 1114 /* 1115 * Builtin commands. Builtin commands whose functions are closely 1116 * tied to evaluation are implemented here. 1117 */ 1118 1119 /* 1120 * No command given. 1121 */ 1122 1123 int 1124 bltincmd(int argc, char **argv) 1125 { 1126 /* 1127 * Preserve exitstatus of a previous possible redirection 1128 * as POSIX mandates 1129 */ 1130 return back_exitstatus; 1131 } 1132 1133 1134 /* 1135 * Handle break and continue commands. Break, continue, and return are 1136 * all handled by setting the evalskip flag. The evaluation routines 1137 * above all check this flag, and if it is set they start skipping 1138 * commands rather than executing them. The variable skipcount is 1139 * the number of loops to break/continue, or the number of function 1140 * levels to return. (The latter is always 1.) It should probably 1141 * be an error to break out of more loops than exist, but it isn't 1142 * in the standard shell so we don't make it one here. 1143 */ 1144 1145 int 1146 breakcmd(int argc, char **argv) 1147 { 1148 int n = argc > 1 ? number(argv[1]) : 1; 1149 1150 if (n > loopnest) 1151 n = loopnest; 1152 if (n > 0) { 1153 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1154 skipcount = n; 1155 } 1156 return 0; 1157 } 1158 1159 1160 /* 1161 * The return command. 1162 */ 1163 1164 int 1165 returncmd(int argc, char **argv) 1166 { 1167 int ret = argc > 1 ? number(argv[1]) : exitstatus; 1168 1169 if (funcnest) { 1170 evalskip = SKIPFUNC; 1171 skipcount = 1; 1172 return ret; 1173 } 1174 else { 1175 /* Do what ksh does; skip the rest of the file */ 1176 evalskip = SKIPFILE; 1177 skipcount = 1; 1178 return ret; 1179 } 1180 } 1181 1182 1183 int 1184 falsecmd(int argc, char **argv) 1185 { 1186 return 1; 1187 } 1188 1189 1190 int 1191 truecmd(int argc, char **argv) 1192 { 1193 return 0; 1194 } 1195 1196 1197 int 1198 execcmd(int argc, char **argv) 1199 { 1200 if (argc > 1) { 1201 struct strlist *sp; 1202 1203 iflag = 0; /* exit on error */ 1204 mflag = 0; 1205 optschanged(); 1206 for (sp = cmdenviron; sp; sp = sp->next) 1207 setvareq(sp->text, VEXPORT|VSTACK); 1208 shellexec(argv + 1, environment(), pathval(), 0, 0); 1209 } 1210 return 0; 1211 } 1212 1213 static int 1214 conv_time(clock_t ticks, char *seconds, size_t l) 1215 { 1216 static clock_t tpm = 0; 1217 clock_t mins; 1218 int i; 1219 1220 if (!tpm) 1221 tpm = sysconf(_SC_CLK_TCK) * 60; 1222 1223 mins = ticks / tpm; 1224 snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm ); 1225 1226 if (seconds[0] == '6' && seconds[1] == '0') { 1227 /* 59.99995 got rounded up... */ 1228 mins++; 1229 strlcpy(seconds, "0.0", l); 1230 return mins; 1231 } 1232 1233 /* suppress trailing zeros */ 1234 i = strlen(seconds) - 1; 1235 for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--) 1236 seconds[i] = 0; 1237 return mins; 1238 } 1239 1240 int 1241 timescmd(int argc, char **argv) 1242 { 1243 struct tms tms; 1244 int u, s, cu, cs; 1245 char us[8], ss[8], cus[8], css[8]; 1246 1247 nextopt(""); 1248 1249 times(&tms); 1250 1251 u = conv_time(tms.tms_utime, us, sizeof(us)); 1252 s = conv_time(tms.tms_stime, ss, sizeof(ss)); 1253 cu = conv_time(tms.tms_cutime, cus, sizeof(cus)); 1254 cs = conv_time(tms.tms_cstime, css, sizeof(css)); 1255 1256 outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n", 1257 u, us, s, ss, cu, cus, cs, css); 1258 1259 return 0; 1260 } 1261