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