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