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