1/*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1997-2005 5 * Herbert Xu <herbert@gondor.apana.org.au>. 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 <zircon/process.h> 36#include <zircon/status.h> 37#include <zircon/syscalls.h> 38#include <stdlib.h> 39#include <signal.h> 40#include <unistd.h> 41#include <sys/types.h> 42 43/* 44 * Evaluate a command. 45 */ 46 47#include "process.h" 48#include "shell.h" 49#include "nodes.h" 50#include "syntax.h" 51#include "expand.h" 52#include "parser.h" 53#include "jobs.h" 54#include "eval.h" 55#include "builtins.h" 56#include "options.h" 57#include "exec.h" 58#include "redir.h" 59#include "input.h" 60#include "output.h" 61#include "trap.h" 62#include "var.h" 63#include "memalloc.h" 64#include "error.h" 65#include "show.h" 66#include "mystring.h" 67 68 69int evalskip; /* set if we are skipping commands */ 70STATIC int skipcount; /* number of levels to skip */ 71MKINIT int loopnest; /* current loop nesting level */ 72static int funcline; /* starting line number of current function, or 0 if not in a function */ 73 74 75char *commandname; 76int exitstatus; /* exit status of last command */ 77int back_exitstatus; /* exit status of backquoted command */ 78int savestatus = -1; /* exit status of last command outside traps */ 79 80 81STATIC int evalloop(union node *, int); 82STATIC int evalfor(union node *, int); 83STATIC int evalcase(union node *, int); 84STATIC int evalsubshell(union node *, int); 85STATIC void expredir(union node *); 86STATIC int evalpipe(union node *, int); 87#ifdef notyet 88STATIC int evalcommand(union node *, int, struct backcmd *); 89#else 90STATIC int evalcommand(union node *, int); 91#endif 92STATIC int evalbltin(const struct builtincmd *, int, char **, int); 93STATIC int evalfun(struct funcnode *, int, char **, int); 94STATIC void prehash(union node *); 95STATIC int eprintlist(struct output *, struct strlist *, int); 96STATIC int bltincmd(int, char **); 97 98 99STATIC const struct builtincmd bltin = { 100 name: nullstr, 101 builtin: bltincmd 102}; 103 104 105/* 106 * Called to reset things after an exception. 107 */ 108 109#ifdef mkinit 110INCLUDE "eval.h" 111 112RESET { 113 evalskip = 0; 114 loopnest = 0; 115 if (savestatus >= 0) { 116 exitstatus = savestatus; 117 savestatus = -1; 118 } 119} 120#endif 121 122 123/* 124 * The eval commmand. 125 */ 126 127static int evalcmd(int argc, char **argv, int flags) 128{ 129 char *p; 130 char *concat; 131 char **ap; 132 133 if (argc > 1) { 134 p = argv[1]; 135 if (argc > 2) { 136 STARTSTACKSTR(concat); 137 ap = argv + 2; 138 for (;;) { 139 concat = stputs(p, concat); 140 if ((p = *ap++) == NULL) 141 break; 142 STPUTC(' ', concat); 143 } 144 STPUTC('\0', concat); 145 p = grabstackstr(concat); 146 } 147 return evalstring(p, flags & EV_TESTED); 148 } 149 return 0; 150} 151 152 153/* 154 * Execute a command or commands contained in a string. 155 */ 156 157int 158evalstring(char *s, int flags) 159{ 160 union node *n; 161 struct stackmark smark; 162 int status; 163 164 s = sstrdup(s); 165 setinputstring(s); 166 setstackmark(&smark); 167 168 status = 0; 169 for (; (n = parsecmd(0)) != NEOF; popstackmark(&smark)) { 170 int i; 171 172 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT)); 173 if (n) 174 status = i; 175 176 if (evalskip) 177 break; 178 } 179 popstackmark(&smark); 180 popfile(); 181 stunalloc(s); 182 183 return status; 184} 185 186 187 188/* 189 * Evaluate a parse tree. The value is left in the global variable 190 * exitstatus. 191 */ 192 193int 194evaltree(union node *n, int flags) 195{ 196 int checkexit = 0; 197 int (*evalfn)(union node *, int); 198 unsigned isor; 199 int status = 0; 200 if (n == NULL) { 201 TRACE(("evaltree(NULL) called\n")); 202 goto out; 203 } 204 205 dotrap(); 206 207 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 208 getpid(), n, n->type, flags)); 209 switch (n->type) { 210 default: 211#ifdef DEBUG 212 out1fmt("Node type = %d\n", n->type); 213#ifndef USE_GLIBC_STDIO 214 flushout(out1); 215#endif 216 break; 217#endif 218 case NNOT: 219 status = !evaltree(n->nnot.com, EV_TESTED); 220 goto setstatus; 221 case NREDIR: 222 errlinno = lineno = n->nredir.linno; 223 if (funcline) 224 lineno -= funcline - 1; 225 expredir(n->nredir.redirect); 226 pushredir(n->nredir.redirect); 227 status = redirectsafe(n->nredir.redirect, REDIR_PUSH) ?: 228 evaltree(n->nredir.n, flags & EV_TESTED); 229 if (n->nredir.redirect) 230 popredir(0); 231 goto setstatus; 232 case NCMD: 233#ifdef notyet 234 if (eflag && !(flags & EV_TESTED)) 235 checkexit = ~0; 236 status = evalcommand(n, flags, (struct backcmd *)NULL); 237 goto setstatus; 238#else 239 evalfn = evalcommand; 240checkexit: 241 if (eflag && !(flags & EV_TESTED)) 242 checkexit = ~0; 243 goto calleval; 244#endif 245 case NFOR: 246 evalfn = evalfor; 247 goto calleval; 248 case NWHILE: 249 case NUNTIL: 250 evalfn = evalloop; 251 goto calleval; 252 case NSUBSHELL: 253 case NBACKGND: 254 evalfn = evalsubshell; 255 goto checkexit; 256 case NPIPE: 257 evalfn = evalpipe; 258 goto checkexit; 259 case NCASE: 260 evalfn = evalcase; 261 goto calleval; 262 case NAND: 263 case NOR: 264 case NSEMI: 265#if NAND + 1 != NOR 266#error NAND + 1 != NOR 267#endif 268#if NOR + 1 != NSEMI 269#error NOR + 1 != NSEMI 270#endif 271 isor = n->type - NAND; 272 status = evaltree(n->nbinary.ch1, 273 (flags | ((isor >> 1) - 1)) & EV_TESTED); 274 if (!status == isor || evalskip) 275 break; 276 n = n->nbinary.ch2; 277evaln: 278 evalfn = evaltree; 279calleval: 280 status = evalfn(n, flags); 281 goto setstatus; 282 case NIF: 283 status = evaltree(n->nif.test, EV_TESTED); 284 if (evalskip) 285 break; 286 if (!status) { 287 n = n->nif.ifpart; 288 goto evaln; 289 } else if (n->nif.elsepart) { 290 n = n->nif.elsepart; 291 goto evaln; 292 } 293 status = 0; 294 goto setstatus; 295 case NDEFUN: 296 defun(n); 297setstatus: 298 exitstatus = status; 299 break; 300 } 301out: 302 if (checkexit & status) 303 goto exexit; 304 305 dotrap(); 306 307 if (flags & EV_EXIT) { 308exexit: 309 exraise(EXEXIT); 310 } 311 312 return exitstatus; 313} 314 315 316void evaltreenr(union node *n, int flags) 317#ifdef HAVE_ATTRIBUTE_ALIAS 318 __attribute__ ((alias("evaltree"))); 319#else 320{ 321 evaltree(n, flags); 322 abort(); 323} 324#endif 325 326 327static int skiploop(void) 328{ 329 int skip = evalskip; 330 331 switch (skip) { 332 case 0: 333 break; 334 335 case SKIPBREAK: 336 case SKIPCONT: 337 if (likely(--skipcount <= 0)) { 338 evalskip = 0; 339 break; 340 } 341 342 skip = SKIPBREAK; 343 break; 344 } 345 346 return skip; 347} 348 349 350STATIC int 351evalloop(union node *n, int flags) 352{ 353 int skip; 354 int status; 355 356 loopnest++; 357 status = 0; 358 flags &= EV_TESTED; 359 do { 360 int i; 361 362 i = evaltree(n->nbinary.ch1, EV_TESTED); 363 skip = skiploop(); 364 if (skip == SKIPFUNC) 365 status = i; 366 if (skip) 367 continue; 368 if (n->type != NWHILE) 369 i = !i; 370 if (i != 0) 371 break; 372 status = evaltree(n->nbinary.ch2, flags); 373 if (status == ZX_ERR_CANCELED) { 374 evalskip = SKIPBREAK; 375 } 376 skip = skiploop(); 377 } while (!(skip & ~SKIPCONT)); 378 loopnest--; 379 380 return status; 381} 382 383 384 385STATIC int 386evalfor(union node *n, int flags) 387{ 388 struct arglist arglist; 389 union node *argp; 390 struct strlist *sp; 391 struct stackmark smark; 392 int status; 393 394 errlinno = lineno = n->nfor.linno; 395 if (funcline) 396 lineno -= funcline - 1; 397 398 setstackmark(&smark); 399 arglist.lastp = &arglist.list; 400 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 401 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 402 } 403 *arglist.lastp = NULL; 404 405 status = 0; 406 loopnest++; 407 flags &= EV_TESTED; 408 for (sp = arglist.list ; sp ; sp = sp->next) { 409 setvar(n->nfor.var, sp->text, 0); 410 status = evaltree(n->nfor.body, flags); 411 if (status == ZX_ERR_CANCELED) { 412 evalskip = SKIPBREAK; 413 } 414 if (skiploop() & ~SKIPCONT) 415 break; 416 } 417 loopnest--; 418 popstackmark(&smark); 419 420 return status; 421} 422 423 424 425STATIC int 426evalcase(union node *n, int flags) 427{ 428 union node *cp; 429 union node *patp; 430 struct arglist arglist; 431 struct stackmark smark; 432 int status = 0; 433 434 errlinno = lineno = n->ncase.linno; 435 if (funcline) 436 lineno -= funcline - 1; 437 438 setstackmark(&smark); 439 arglist.lastp = &arglist.list; 440 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 441 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 442 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 443 if (casematch(patp, arglist.list->text)) { 444 /* Ensure body is non-empty as otherwise 445 * EV_EXIT may prevent us from setting the 446 * exit status. 447 */ 448 if (evalskip == 0 && cp->nclist.body) { 449 status = evaltree(cp->nclist.body, 450 flags); 451 } 452 goto out; 453 } 454 } 455 } 456out: 457 popstackmark(&smark); 458 459 return status; 460} 461 462 463 464/* 465 * Kick off a subshell to evaluate a tree. 466 */ 467 468STATIC int 469evalsubshell(union node *n, int flags) 470{ 471 struct job *jp; 472 int backgnd = (n->type == NBACKGND); 473 int status; 474 475 errlinno = lineno = n->nredir.linno; 476 if (funcline) 477 lineno -= funcline - 1; 478 479 expredir(n->nredir.redirect); 480 if (!backgnd && flags & EV_EXIT && !have_traps()) { 481 redirect(n->nredir.redirect, 0); 482 evaltreenr(n->nredir.n, flags); 483 /* never returns */ 484 } 485 INTOFF; 486 jp = makejob(n, 1); 487 zx_handle_t process; 488 const char* const* envp = (const char* const*)environment(); 489 490 // Run in the foreground (of the subshell running in the background) 491 if (backgnd) 492 n->type = NSUBSHELL; 493 494 char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 495 zx_status_t exec_result = process_subshell(n, envp, &process, jp->zx_job_hndl, NULL, err_msg); 496 if (exec_result == ZX_OK) { 497 /* Process-tracking management */ 498 forkparent(jp, n, backgnd, process); 499 } else { 500 sh_error("Failed to create subshell: %d (%s): %s", exec_result, zx_status_get_string(exec_result), err_msg); 501 return exec_result; 502 } 503 status = 0; 504 if (! backgnd) { 505 status = process_await_termination(process, jp->zx_job_hndl, true); 506 zx_handle_close(process); 507 } 508 INTON; 509 return status; 510} 511 512 513/* 514 * Compute the names of the files in a redirection list. 515 */ 516 517STATIC void 518expredir(union node *n) 519{ 520 union node *redir; 521 522 for (redir = n ; redir ; redir = redir->nfile.next) { 523 struct arglist fn; 524 fn.lastp = &fn.list; 525 switch (redir->type) { 526 case NFROMTO: 527 case NFROM: 528 case NTO: 529 case NCLOBBER: 530 case NAPPEND: 531 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 532 redir->nfile.expfname = fn.list->text; 533 break; 534 case NFROMFD: 535 case NTOFD: 536 if (redir->ndup.vname) { 537 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 538 fixredir(redir, fn.list->text, 1); 539 } 540 break; 541 } 542 } 543} 544 545 546 547/* 548 * Evaluate a pipeline. All the processes in the pipeline are children 549 * of the process creating the pipeline. (This differs from some versions 550 * of the shell, which make the last process in a pipeline the parent 551 * of all the rest.) 552 */ 553 554STATIC int 555evalpipe(union node *n, int flags) 556{ 557 struct job *jp; 558 struct nodelist *lp; 559 int pipelen; 560 int fds[3] = { STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO }; 561 int pip[2] = { -1, -1 }; 562 int status = 0; 563 564 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 565 pipelen = 0; 566 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 567 pipelen++; 568 flags |= EV_EXIT; 569 INTOFF; 570 jp = makejob(n, pipelen); 571 572 const size_t processes_size = pipelen * sizeof(zx_handle_t); 573 zx_handle_t* processes = ckmalloc(processes_size); 574 memset(processes, 0, processes_size); 575 576 size_t idx = 0u; 577 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next, ++idx) { 578 prehash(lp->n); 579 if (pip[0] > 0) 580 fds[0] = pip[0]; 581 if (lp->next) { 582 if (pipe(pip) < 0) 583 sh_error("Pipe call failed"); 584 fds[1] = pip[1]; 585 } else { 586 fds[1] = STDOUT_FILENO; 587 } 588 char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 589 const char* const* envp = (const char* const*)environment(); 590 zx_status_t status = process_subshell(lp->n, envp, &processes[idx], jp->zx_job_hndl, fds, err_msg); 591 if (fds[0] != STDIN_FILENO) 592 close(fds[0]); 593 if (fds[1] != STDOUT_FILENO) 594 close(fds[1]); 595 if (status == ZX_OK) { 596 /* Process-tracking management */ 597 forkparent(jp, lp->n, FORK_NOJOB, processes[idx]); 598 } else { 599 freejob(jp); 600 sh_error("Failed to create shell: %d (%s): %s", status, zx_status_get_string(status), err_msg); 601 } 602 } 603 604 if (n->npipe.backgnd == 0) { 605 status = waitforjob(jp); 606 TRACE(("evalpipe: job done exit status: %d (%s)\n", status, zx_status_get_string(status))); 607 } 608 INTON; 609 610 zx_handle_close_many(processes, pipelen); 611 ckfree(processes); 612 613 return status; 614} 615 616 617 618/* 619 * Execute a command inside back quotes. If it's a builtin command, we 620 * want to save its output in a block obtained from malloc. Otherwise 621 * we fork off a subprocess and get the output of the command via a pipe. 622 * Should be called with interrupts off. 623 */ 624 625void 626evalbackcmd(union node *n, struct backcmd *result) 627{ 628 int pip[2]; 629 struct job *jp; 630 631 result->fd = -1; 632 result->buf = NULL; 633 result->nleft = 0; 634 result->jp = NULL; 635 if (n == NULL) { 636 goto out; 637 } 638 639 if (pipe(pip) < 0) 640 sh_error("Pipe call failed"); 641 jp = makejob(n, 1); 642 zx_handle_t process; 643 char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 644 const char* const* envp = (const char* const*)environment(); 645 int fds[3] = { STDIN_FILENO, pip[1], STDERR_FILENO }; 646 zx_status_t status = process_subshell(n, envp, &process, jp->zx_job_hndl, &fds[0], err_msg); 647 close(pip[1]); 648 if (status != ZX_OK) { 649 freejob(jp); 650 sh_error("Failed to create subshell: %d (%s): %s", status, zx_status_get_string(status), err_msg); 651 } else { 652 /* Process-tracking management */ 653 forkparent(jp, n, FORK_NOJOB, process); 654 result->fd = pip[0]; 655 result->jp = jp; 656 } 657 658out: 659 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 660 result->fd, result->buf, result->nleft, result->jp)); 661} 662 663static char ** 664parse_command_args(char **argv, const char **path) 665{ 666 char *cp, c; 667 668 for (;;) { 669 cp = *++argv; 670 if (!cp) 671 return 0; 672 if (*cp++ != '-') 673 break; 674 if (!(c = *cp++)) 675 break; 676 if (c == '-' && !*cp) { 677 if (!*++argv) 678 return 0; 679 break; 680 } 681 do { 682 switch (c) { 683 case 'p': 684 *path = defpath; 685 break; 686 default: 687 /* run 'typecmd' for other options */ 688 return 0; 689 } 690 } while ((c = *cp++)); 691 } 692 return argv; 693} 694 695 696 697/* 698 * Execute a simple command. 699 */ 700 701STATIC int 702#ifdef notyet 703evalcommand(union node *cmd, int flags, struct backcmd *backcmd) 704#else 705evalcommand(union node *cmd, int flags) 706#endif 707{ 708 struct localvar_list *localvar_stop; 709 struct redirtab *redir_stop; 710 struct stackmark smark; 711 union node *argp; 712 struct arglist arglist; 713 struct arglist varlist; 714 char **argv; 715 int argc; 716 struct strlist *sp; 717#ifdef notyet 718 int pip[2]; 719#endif 720 struct cmdentry cmdentry; 721 char *lastarg; 722 const char *path; 723 int spclbltin; 724 int execcmd; 725 int status; 726 char **nargv; 727 728 errlinno = lineno = cmd->ncmd.linno; 729 if (funcline) 730 lineno -= funcline - 1; 731 732 /* First expand the arguments. */ 733 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 734 setstackmark(&smark); 735 localvar_stop = pushlocalvars(); 736 back_exitstatus = 0; 737 738 cmdentry.cmdtype = CMDBUILTIN; 739 cmdentry.u.cmd = &bltin; 740 varlist.lastp = &varlist.list; 741 *varlist.lastp = NULL; 742 arglist.lastp = &arglist.list; 743 *arglist.lastp = NULL; 744 745 argc = 0; 746 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 747 struct strlist **spp; 748 749 spp = arglist.lastp; 750 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 751 for (sp = *spp; sp; sp = sp->next) 752 argc++; 753 } 754 755 /* Reserve one extra spot at the front for shellexec. */ 756 nargv = stalloc(sizeof (char *) * (argc + 2)); 757 argv = ++nargv; 758 for (sp = arglist.list ; sp ; sp = sp->next) { 759 TRACE(("evalcommand arg: %s\n", sp->text)); 760 *nargv++ = sp->text; 761 } 762 *nargv = NULL; 763 764 lastarg = NULL; 765 if (iflag && funcline == 0 && argc > 0) 766 lastarg = nargv[-1]; 767 768 preverrout.fd = 2; 769 expredir(cmd->ncmd.redirect); 770 redir_stop = pushredir(cmd->ncmd.redirect); 771 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); 772 773 path = vpath.text; 774 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 775 struct strlist **spp; 776 char *p; 777 778 spp = varlist.lastp; 779 expandarg(argp, &varlist, EXP_VARTILDE); 780 781 mklocal((*spp)->text); 782 783 /* 784 * Modify the command lookup path, if a PATH= assignment 785 * is present 786 */ 787 p = (*spp)->text; 788 if (varequal(p, path)) 789 path = p; 790 } 791 792 /* Print the command if xflag is set. */ 793 if (xflag) { 794 struct output *out; 795 int sep; 796 797 out = &preverrout; 798 outstr(expandstr(ps4val()), out); 799 sep = 0; 800 sep = eprintlist(out, varlist.list, sep); 801 eprintlist(out, arglist.list, sep); 802 outcslow('\n', out); 803#ifdef FLUSHERR 804 flushout(out); 805#endif 806 } 807 808 execcmd = 0; 809 spclbltin = -1; 810 811 /* Now locate the command. */ 812 if (argc) { 813 const char *oldpath; 814 int cmd_flag = DO_ERR; 815 816 path += 5; 817 oldpath = path; 818 for (;;) { 819 find_command(argv[0], &cmdentry, cmd_flag, path); 820 if (cmdentry.cmdtype == CMDUNKNOWN) { 821 status = 127; 822#ifdef FLUSHERR 823 flushout(&errout); 824#endif 825 goto bail; 826 } 827 828 /* implement bltin and command here */ 829 if (cmdentry.cmdtype != CMDBUILTIN) 830 break; 831 if (spclbltin < 0) 832 spclbltin = 833 cmdentry.u.cmd->flags & 834 BUILTIN_SPECIAL 835 ; 836 if (cmdentry.u.cmd == EXECCMD) 837 execcmd++; 838 if (cmdentry.u.cmd != COMMANDCMD) 839 break; 840 841 path = oldpath; 842 nargv = parse_command_args(argv, &path); 843 if (!nargv) 844 break; 845 argc -= nargv - argv; 846 argv = nargv; 847 cmd_flag |= DO_NOFUNC; 848 } 849 } 850 851 if (status) { 852bail: 853 exitstatus = status; 854 855 /* We have a redirection error. */ 856 if (spclbltin > 0) 857 exraise(EXERROR); 858 859 goto out; 860 } 861 862 /* Execute the command. */ 863 switch (cmdentry.cmdtype) { 864 default: { 865 zx_handle_t process = ZX_HANDLE_INVALID; 866 zx_handle_t zx_job_hndl; 867 zx_status_t zx_status = zx_job_create(zx_job_default(), 0, &zx_job_hndl); 868 if (zx_status != ZX_OK) { 869 sh_error("Cannot create child process: %d (%s)", zx_status, zx_status_get_string(zx_status)); 870 break; 871 } 872 char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 873 status = process_launch((const char* const*)argv, path, cmdentry.u.index, &process, zx_job_hndl, &zx_status, err_msg); 874 if (status) { 875 sh_error("Cannot create child process: %d (%s): %s", zx_status, zx_status_get_string(zx_status), err_msg); 876 break; 877 } 878 settitle(argv[0]); 879 status = process_await_termination(process, zx_job_hndl, true); 880 zx_handle_close(process); 881 zx_handle_close(zx_job_hndl); 882 settitle("sh"); 883 break; 884 } 885 case CMDBUILTIN: 886 if (spclbltin > 0 || argc == 0) { 887 poplocalvars(1); 888 if (execcmd && argc > 1) 889 listsetvar(varlist.list, VEXPORT); 890 } 891 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { 892 if (exception == EXERROR && spclbltin <= 0) { 893 FORCEINTON; 894 goto readstatus; 895 } 896raise: 897 longjmp(handler->loc, 1); 898 } 899 goto readstatus; 900 901 case CMDFUNCTION: 902 poplocalvars(1); 903 if (evalfun(cmdentry.u.func, argc, argv, flags)) 904 goto raise; 905readstatus: 906 status = exitstatus; 907 break; 908 } 909 910out: 911 if (cmd->ncmd.redirect) 912 popredir(execcmd); 913 unwindredir(redir_stop); 914 unwindlocalvars(localvar_stop); 915 if (lastarg) 916 /* dsl: I think this is intended to be used to support 917 * '_' in 'vi' command mode during line editing... 918 * However I implemented that within libedit itself. 919 */ 920 setvar("_", lastarg, 0); 921 popstackmark(&smark); 922 923 return status; 924} 925 926STATIC int 927evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags) 928{ 929 char *volatile savecmdname; 930 struct jmploc *volatile savehandler; 931 struct jmploc jmploc; 932 int status; 933 int i; 934 935 savecmdname = commandname; 936 savehandler = handler; 937 if ((i = setjmp(jmploc.loc))) 938 goto cmddone; 939 handler = &jmploc; 940 commandname = argv[0]; 941 argptr = argv + 1; 942 optptr = NULL; /* initialize nextopt */ 943 if (cmd == EVALCMD) 944 status = evalcmd(argc, argv, flags); 945 else 946 status = (*cmd->builtin)(argc, argv); 947 flushall(); 948 status |= outerr(out1); 949 exitstatus = status; 950cmddone: 951 freestdout(); 952 commandname = savecmdname; 953 handler = savehandler; 954 955 return i; 956} 957 958STATIC int 959evalfun(struct funcnode *func, int argc, char **argv, int flags) 960{ 961 volatile struct shparam saveparam; 962 struct jmploc *volatile savehandler; 963 struct jmploc jmploc; 964 int e; 965 int savefuncline; 966 int saveloopnest; 967 968 saveparam = shellparam; 969 savefuncline = funcline; 970 saveloopnest = loopnest; 971 savehandler = handler; 972 if ((e = setjmp(jmploc.loc))) { 973 goto funcdone; 974 } 975 INTOFF; 976 handler = &jmploc; 977 shellparam.malloc = 0; 978 func->count++; 979 funcline = func->n.ndefun.linno; 980 loopnest = 0; 981 INTON; 982 shellparam.nparam = argc - 1; 983 shellparam.p = argv + 1; 984 shellparam.optind = 1; 985 shellparam.optoff = -1; 986 pushlocalvars(); 987 evaltree(func->n.ndefun.body, flags & EV_TESTED); 988 poplocalvars(0); 989funcdone: 990 INTOFF; 991 loopnest = saveloopnest; 992 funcline = savefuncline; 993 freefunc(func); 994 freeparam(&shellparam); 995 shellparam = saveparam; 996 handler = savehandler; 997 INTON; 998 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF); 999 return e; 1000} 1001 1002 1003/* 1004 * Search for a command. This is called before we fork so that the 1005 * location of the command will be available in the parent as well as 1006 * the child. The check for "goodname" is an overly conservative 1007 * check that the name will not be subject to expansion. 1008 */ 1009 1010STATIC void 1011prehash(union node *n) 1012{ 1013 struct cmdentry entry; 1014 1015 if (n->type == NCMD && n->ncmd.args) 1016 if (goodname(n->ncmd.args->narg.text)) 1017 find_command(n->ncmd.args->narg.text, &entry, 0, 1018 pathval()); 1019} 1020 1021 1022 1023/* 1024 * Builtin commands. Builtin commands whose functions are closely 1025 * tied to evaluation are implemented here. 1026 */ 1027 1028/* 1029 * No command given. 1030 */ 1031 1032STATIC int 1033bltincmd(int argc, char **argv) 1034{ 1035 /* 1036 * Preserve exitstatus of a previous possible redirection 1037 * as POSIX mandates 1038 */ 1039 return back_exitstatus; 1040} 1041 1042 1043/* 1044 * Handle break and continue commands. Break, continue, and return are 1045 * all handled by setting the evalskip flag. The evaluation routines 1046 * above all check this flag, and if it is set they start skipping 1047 * commands rather than executing them. The variable skipcount is 1048 * the number of loops to break/continue, or the number of function 1049 * levels to return. (The latter is always 1.) It should probably 1050 * be an error to break out of more loops than exist, but it isn't 1051 * in the standard shell so we don't make it one here. 1052 */ 1053 1054int 1055breakcmd(int argc, char **argv) 1056{ 1057 int n = argc > 1 ? number(argv[1]) : 1; 1058 1059 if (n <= 0) 1060 badnum(argv[1]); 1061 if (n > loopnest) 1062 n = loopnest; 1063 if (n > 0) { 1064 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1065 skipcount = n; 1066 } 1067 return 0; 1068} 1069 1070 1071/* 1072 * The return command. 1073 */ 1074 1075int 1076returncmd(int argc, char **argv) 1077{ 1078 int skip; 1079 int status; 1080 1081 /* 1082 * If called outside a function, do what ksh does; 1083 * skip the rest of the file. 1084 */ 1085 if (argv[1]) { 1086 skip = SKIPFUNC; 1087 status = number(argv[1]); 1088 } else { 1089 skip = SKIPFUNCDEF; 1090 status = exitstatus; 1091 } 1092 evalskip = skip; 1093 1094 return status; 1095} 1096 1097 1098int 1099falsecmd(int argc, char **argv) 1100{ 1101 return 1; 1102} 1103 1104 1105int 1106truecmd(int argc, char **argv) 1107{ 1108 return 0; 1109} 1110 1111 1112int 1113execcmd(int argc, char **argv) 1114{ 1115 if (argc > 1) { 1116 iflag = 0; /* exit on error */ 1117 mflag = 0; 1118 optschanged(); 1119 shellexec(argv + 1, pathval(), 0); 1120 } 1121 return 0; 1122} 1123 1124 1125STATIC int 1126eprintlist(struct output *out, struct strlist *sp, int sep) 1127{ 1128 while (sp) { 1129 const char *p; 1130 1131 p = " %s" + (1 - sep); 1132 sep |= 1; 1133 outfmt(out, p, sp->text); 1134 sp = sp->next; 1135 } 1136 1137 return sep; 1138} 1139