eval.c revision 201053
111820Sjulian/*- 211820Sjulian * Copyright (c) 1993 311820Sjulian * The Regents of the University of California. All rights reserved. 411820Sjulian * 511820Sjulian * This code is derived from software contributed to Berkeley by 611820Sjulian * Kenneth Almquist. 711820Sjulian * 811820Sjulian * Redistribution and use in source and binary forms, with or without 911820Sjulian * modification, are permitted provided that the following conditions 1011820Sjulian * are met: 1111820Sjulian * 1. Redistributions of source code must retain the above copyright 1211820Sjulian * notice, this list of conditions and the following disclaimer. 1311820Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1411820Sjulian * notice, this list of conditions and the following disclaimer in the 1511820Sjulian * documentation and/or other materials provided with the distribution. 1611820Sjulian * 4. Neither the name of the University nor the names of its contributors 1711820Sjulian * may be used to endorse or promote products derived from this software 1811820Sjulian * without specific prior written permission. 1911820Sjulian * 2011820Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2111820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2211820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2311820Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2411820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2511820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2611820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2711820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2811820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2911820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3011820Sjulian * SUCH DAMAGE. 3111820Sjulian */ 3211820Sjulian 3311820Sjulian#ifndef lint 3411820Sjulian#if 0 3511820Sjulianstatic char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 3611820Sjulian#endif 3711820Sjulian#endif /* not lint */ 3850306Sjhay#include <sys/cdefs.h> 3911820Sjulian__FBSDID("$FreeBSD: head/bin/sh/eval.c 201053 2009-12-27 18:04:05Z jilles $"); 4011820Sjulian 4111820Sjulian#include <paths.h> 4211820Sjulian#include <signal.h> 4311820Sjulian#include <stdlib.h> 4411820Sjulian#include <unistd.h> 4511820Sjulian#include <sys/resource.h> 4611820Sjulian#include <sys/wait.h> /* For WIFSIGNALED(status) */ 4711820Sjulian#include <errno.h> 4811820Sjulian 4911820Sjulian/* 5011820Sjulian * Evaluate a command. 5111820Sjulian */ 5211820Sjulian 5311820Sjulian#include "shell.h" 5411820Sjulian#include "nodes.h" 5511820Sjulian#include "syntax.h" 5611820Sjulian#include "expand.h" 5711820Sjulian#include "parser.h" 5811820Sjulian#include "jobs.h" 5911820Sjulian#include "eval.h" 6011820Sjulian#include "builtins.h" 6111820Sjulian#include "options.h" 6211820Sjulian#include "exec.h" 6311820Sjulian#include "redir.h" 6411820Sjulian#include "input.h" 6511820Sjulian#include "output.h" 6611820Sjulian#include "trap.h" 6711820Sjulian#include "var.h" 6811820Sjulian#include "memalloc.h" 6911820Sjulian#include "error.h" 7011820Sjulian#include "show.h" 7111820Sjulian#include "mystring.h" 7211820Sjulian#ifndef NO_HISTORY 7311820Sjulian#include "myhistedit.h" 7411820Sjulian#endif 7511820Sjulian 7611820Sjulian 7711820Sjulianint evalskip; /* set if we are skipping commands */ 7811820SjulianSTATIC int skipcount; /* number of levels to skip */ 7911820SjulianMKINIT int loopnest; /* current loop nesting level */ 8011820Sjulianint funcnest; /* depth of function calls */ 8111820SjulianSTATIC int builtin_flags; /* evalcommand flags for builtins */ 8215248Sjhay 8311820Sjulian 8411820Sjulianchar *commandname; 8511820Sjulianstruct strlist *cmdenviron; 8611820Sjulianint exitstatus; /* exit status of last command */ 8711820Sjulianint oexitstatus; /* saved exit status */ 8827244Sjhay 8927244Sjhay 9011820SjulianSTATIC void evalloop(union node *, int); 9111840SjulianSTATIC void evalfor(union node *, int); 9211820SjulianSTATIC void evalcase(union node *, int); 9311840SjulianSTATIC void evalsubshell(union node *, int); 9411820SjulianSTATIC void expredir(union node *); 9511820SjulianSTATIC void evalpipe(union node *); 9611820SjulianSTATIC void evalcommand(union node *, int, struct backcmd *); 9715248SjhaySTATIC void prehash(union node *); 9827244Sjhay 9911820Sjulian 10011820Sjulian/* 10111820Sjulian * Called to reset things after an exception. 10211820Sjulian */ 10311820Sjulian 10411820Sjulian#ifdef mkinit 10511820SjulianINCLUDE "eval.h" 10611820Sjulian 10727244SjhayRESET { 10827244Sjhay evalskip = 0; 10911820Sjulian loopnest = 0; 11011820Sjulian funcnest = 0; 11111820Sjulian} 11211820Sjulian 11311820SjulianSHELLPROC { 11411820Sjulian exitstatus = 0; 11511820Sjulian} 11611820Sjulian#endif 11711820Sjulian 11811820Sjulian 11911820Sjulian 12011820Sjulian/* 12111820Sjulian * The eval command. 12211820Sjulian */ 12311820Sjulian 12411820Sjulianint 12511820Sjulianevalcmd(int argc, char **argv) 12611820Sjulian{ 12711820Sjulian char *p; 12811820Sjulian char *concat; 12911820Sjulian char **ap; 13011820Sjulian 13111820Sjulian if (argc > 1) { 13211820Sjulian p = argv[1]; 13311820Sjulian if (argc > 2) { 13411820Sjulian STARTSTACKSTR(concat); 13511820Sjulian ap = argv + 2; 13611820Sjulian for (;;) { 13711820Sjulian while (*p) 13811820Sjulian STPUTC(*p++, concat); 13911820Sjulian if ((p = *ap++) == NULL) 14011820Sjulian break; 14111820Sjulian STPUTC(' ', concat); 14211820Sjulian } 14311820Sjulian STPUTC('\0', concat); 14411820Sjulian p = grabstackstr(concat); 14511820Sjulian } 14611820Sjulian evalstring(p, builtin_flags & EV_TESTED); 14711820Sjulian } 14811820Sjulian return exitstatus; 14911820Sjulian} 15045988Sjhay 15145988Sjhay 15245988Sjhay/* 15345988Sjhay * Execute a command or commands contained in a string. 15445988Sjhay */ 15511820Sjulian 15645988Sjhayvoid 15711820Sjulianevalstring(char *s, int flags) 15811820Sjulian{ 15911820Sjulian union node *n; 16011820Sjulian struct stackmark smark; 16111820Sjulian int flags_exit; 16211820Sjulian 16311820Sjulian flags_exit = flags & EV_EXIT; 16411820Sjulian flags &= ~EV_EXIT; 16511820Sjulian setstackmark(&smark); 16611820Sjulian setinputstring(s, 1); 16711820Sjulian while ((n = parsecmd(0)) != NEOF) { 16811820Sjulian if (n != NULL) { 16911820Sjulian if (flags_exit && preadateof()) 17011820Sjulian evaltree(n, flags | EV_EXIT); 17111820Sjulian else 17211820Sjulian evaltree(n, flags); 17311820Sjulian } 17411820Sjulian popstackmark(&smark); 17511820Sjulian } 17611820Sjulian popfile(); 17711820Sjulian popstackmark(&smark); 17811820Sjulian if (flags_exit) 17911820Sjulian exitshell(exitstatus); 18011820Sjulian} 18111820Sjulian 18211820Sjulian 18311820Sjulian/* 18411820Sjulian * Evaluate a parse tree. The value is left in the global variable 18511820Sjulian * exitstatus. 18611820Sjulian */ 18711820Sjulian 18811820Sjulianvoid 18911820Sjulianevaltree(union node *n, int flags) 19011820Sjulian{ 19111820Sjulian int do_etest; 19211820Sjulian 19311820Sjulian do_etest = 0; 19411820Sjulian if (n == NULL) { 19511820Sjulian TRACE(("evaltree(NULL) called\n")); 19611820Sjulian exitstatus = 0; 19711820Sjulian goto out; 19811820Sjulian } 19911820Sjulian#ifndef NO_HISTORY 20011820Sjulian displayhist = 1; /* show history substitutions done with fc */ 20111820Sjulian#endif 20211820Sjulian TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type)); 20311820Sjulian switch (n->type) { 20411820Sjulian case NSEMI: 20511820Sjulian evaltree(n->nbinary.ch1, flags & ~EV_EXIT); 20611820Sjulian if (evalskip) 20711820Sjulian goto out; 20811820Sjulian evaltree(n->nbinary.ch2, flags); 20911820Sjulian break; 21011820Sjulian case NAND: 21111820Sjulian evaltree(n->nbinary.ch1, EV_TESTED); 21211820Sjulian if (evalskip || exitstatus != 0) { 21311820Sjulian goto out; 21411820Sjulian } 21511820Sjulian evaltree(n->nbinary.ch2, flags); 21627244Sjhay break; 21711820Sjulian case NOR: 21811820Sjulian evaltree(n->nbinary.ch1, EV_TESTED); 21911820Sjulian if (evalskip || exitstatus == 0) 22011820Sjulian goto out; 22127244Sjhay evaltree(n->nbinary.ch2, flags); 22211820Sjulian break; 22311820Sjulian case NREDIR: 22427244Sjhay expredir(n->nredir.redirect); 22511820Sjulian redirect(n->nredir.redirect, REDIR_PUSH); 22611820Sjulian evaltree(n->nredir.n, flags); 22711820Sjulian popredir(); 22815248Sjhay break; 22927244Sjhay case NSUBSHELL: 23027244Sjhay evalsubshell(n, flags); 23127244Sjhay do_etest = !(flags & EV_TESTED); 23227244Sjhay break; 23327244Sjhay case NBACKGND: 23427244Sjhay evalsubshell(n, flags); 23527244Sjhay break; 23611820Sjulian case NIF: { 23711820Sjulian evaltree(n->nif.test, EV_TESTED); 23811820Sjulian if (evalskip) 23927244Sjhay goto out; 24027244Sjhay if (exitstatus == 0) 24127244Sjhay evaltree(n->nif.ifpart, flags); 24227244Sjhay else if (n->nif.elsepart) 24327244Sjhay evaltree(n->nif.elsepart, flags); 24427244Sjhay else 24511820Sjulian exitstatus = 0; 24611820Sjulian break; 24711820Sjulian } 24811820Sjulian case NWHILE: 24911820Sjulian case NUNTIL: 25011820Sjulian evalloop(n, flags & ~EV_EXIT); 25111820Sjulian break; 25211820Sjulian case NFOR: 25312692Sjulian evalfor(n, flags & ~EV_EXIT); 25412692Sjulian break; 25512692Sjulian case NCASE: 25612692Sjulian evalcase(n, flags); 25711820Sjulian break; 25811820Sjulian case NDEFUN: 25911820Sjulian defun(n->narg.text, n->narg.next); 26011820Sjulian exitstatus = 0; 26111820Sjulian break; 26211820Sjulian case NNOT: 26311820Sjulian evaltree(n->nnot.com, EV_TESTED); 26427244Sjhay exitstatus = !exitstatus; 26527244Sjhay break; 26627244Sjhay 26727244Sjhay case NPIPE: 26827244Sjhay evalpipe(n); 26927244Sjhay do_etest = !(flags & EV_TESTED); 27011820Sjulian break; 27111820Sjulian case NCMD: 27211820Sjulian evalcommand(n, flags, (struct backcmd *)NULL); 27311820Sjulian do_etest = !(flags & EV_TESTED); 27411820Sjulian break; 27511820Sjulian default: 27611820Sjulian out1fmt("Node type = %d\n", n->type); 27711820Sjulian flushout(&output); 27811820Sjulian break; 27911820Sjulian } 28011840Sjulianout: 28111820Sjulian if (pendingsigs) 28211820Sjulian dotrap(); 28311820Sjulian if ((flags & EV_EXIT) || (eflag && exitstatus != 0 && do_etest)) 28411820Sjulian exitshell(exitstatus); 28511820Sjulian} 28611820Sjulian 28711820Sjulian 28811820SjulianSTATIC void 28911820Sjulianevalloop(union node *n, int flags) 29011840Sjulian{ 29111840Sjulian int status; 29211820Sjulian 29311820Sjulian loopnest++; 29411820Sjulian status = 0; 29511840Sjulian for (;;) { 29611840Sjulian evaltree(n->nbinary.ch1, EV_TESTED); 29711820Sjulian if (evalskip) { 29811820Sjulianskipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 29911820Sjulian evalskip = 0; 30011840Sjulian continue; 30111840Sjulian } 30211820Sjulian if (evalskip == SKIPBREAK && --skipcount <= 0) 30311820Sjulian evalskip = 0; 30411820Sjulian break; 30511840Sjulian } 30611820Sjulian if (n->type == NWHILE) { 30711820Sjulian if (exitstatus != 0) 30811820Sjulian break; 30911820Sjulian } else { 31011820Sjulian if (exitstatus == 0) 31111820Sjulian break; 31211820Sjulian } 31311820Sjulian evaltree(n->nbinary.ch2, flags); 31411820Sjulian status = exitstatus; 31511820Sjulian if (evalskip) 31611820Sjulian goto skipping; 31711820Sjulian } 31811820Sjulian loopnest--; 31911820Sjulian exitstatus = status; 32011820Sjulian} 32111820Sjulian 32211820Sjulian 32311820Sjulian 32411820SjulianSTATIC void 32511820Sjulianevalfor(union node *n, int flags) 32611820Sjulian{ 32711820Sjulian struct arglist arglist; 32811820Sjulian union node *argp; 32911820Sjulian struct strlist *sp; 33011820Sjulian struct stackmark smark; 33111820Sjulian 33211820Sjulian setstackmark(&smark); 33311820Sjulian arglist.lastp = &arglist.list; 33411820Sjulian for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 33511820Sjulian oexitstatus = exitstatus; 33611820Sjulian expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 33711820Sjulian if (evalskip) 33811820Sjulian goto out; 33911820Sjulian } 34011820Sjulian *arglist.lastp = NULL; 34111840Sjulian 34211820Sjulian exitstatus = 0; 34311820Sjulian loopnest++; 34411820Sjulian for (sp = arglist.list ; sp ; sp = sp->next) { 34511820Sjulian setvar(n->nfor.var, sp->text, 0); 34611820Sjulian evaltree(n->nfor.body, flags); 34711840Sjulian if (evalskip) { 34811820Sjulian if (evalskip == SKIPCONT && --skipcount <= 0) { 34927244Sjhay evalskip = 0; 35011840Sjulian continue; 35127244Sjhay } 35227244Sjhay if (evalskip == SKIPBREAK && --skipcount <= 0) 35327244Sjhay evalskip = 0; 35411820Sjulian break; 35511820Sjulian } 35611820Sjulian } 35711820Sjulian loopnest--; 35811820Sjulianout: 35911820Sjulian popstackmark(&smark); 36011820Sjulian} 36111820Sjulian 36211820Sjulian 36311820Sjulian 36411820SjulianSTATIC void 36511820Sjulianevalcase(union node *n, int flags) 36611820Sjulian{ 36711820Sjulian union node *cp; 36811820Sjulian union node *patp; 36911820Sjulian struct arglist arglist; 37011820Sjulian struct stackmark smark; 37111820Sjulian 37211820Sjulian setstackmark(&smark); 37311820Sjulian arglist.lastp = &arglist.list; 37411820Sjulian oexitstatus = exitstatus; 37511820Sjulian exitstatus = 0; 37611820Sjulian expandarg(n->ncase.expr, &arglist, EXP_TILDE); 37711820Sjulian for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 37811820Sjulian for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 37915248Sjhay if (casematch(patp, arglist.list->text)) { 38015248Sjhay if (evalskip == 0) { 38127244Sjhay evaltree(cp->nclist.body, flags); 38227244Sjhay } 38327244Sjhay goto out; 38427244Sjhay } 38527244Sjhay } 38627244Sjhay } 38715248Sjhayout: 38815248Sjhay popstackmark(&smark); 38915248Sjhay} 39015248Sjhay 39150306Sjhay 39215248Sjhay 39315248Sjhay/* 39415248Sjhay * Kick off a subshell to evaluate a tree. 39515248Sjhay */ 39615248Sjhay 39715248SjhaySTATIC void 39815248Sjhayevalsubshell(union node *n, int flags) 39915248Sjhay{ 40015248Sjhay struct job *jp; 401 int backgnd = (n->type == NBACKGND); 402 403 expredir(n->nredir.redirect); 404 if ((!backgnd && flags & EV_EXIT && !have_traps()) || 405 forkshell(jp = makejob(n, 1), n, backgnd) == 0) { 406 if (backgnd) 407 flags &=~ EV_TESTED; 408 redirect(n->nredir.redirect, 0); 409 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 410 } else if (! backgnd) { 411 INTOFF; 412 exitstatus = waitforjob(jp, (int *)NULL); 413 INTON; 414 } 415} 416 417 418 419/* 420 * Compute the names of the files in a redirection list. 421 */ 422 423STATIC void 424expredir(union node *n) 425{ 426 union node *redir; 427 428 for (redir = n ; redir ; redir = redir->nfile.next) { 429 struct arglist fn; 430 fn.lastp = &fn.list; 431 oexitstatus = exitstatus; 432 switch (redir->type) { 433 case NFROM: 434 case NTO: 435 case NFROMTO: 436 case NAPPEND: 437 case NCLOBBER: 438 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 439 redir->nfile.expfname = fn.list->text; 440 break; 441 case NFROMFD: 442 case NTOFD: 443 if (redir->ndup.vname) { 444 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); 445 fixredir(redir, fn.list->text, 1); 446 } 447 break; 448 } 449 } 450} 451 452 453 454/* 455 * Evaluate a pipeline. All the processes in the pipeline are children 456 * of the process creating the pipeline. (This differs from some versions 457 * of the shell, which make the last process in a pipeline the parent 458 * of all the rest.) 459 */ 460 461STATIC void 462evalpipe(union node *n) 463{ 464 struct job *jp; 465 struct nodelist *lp; 466 int pipelen; 467 int prevfd; 468 int pip[2]; 469 470 TRACE(("evalpipe(%p) called\n", (void *)n)); 471 pipelen = 0; 472 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 473 pipelen++; 474 INTOFF; 475 jp = makejob(n, pipelen); 476 prevfd = -1; 477 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 478 prehash(lp->n); 479 pip[1] = -1; 480 if (lp->next) { 481 if (pipe(pip) < 0) { 482 close(prevfd); 483 error("Pipe call failed: %s", strerror(errno)); 484 } 485 } 486 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 487 INTON; 488 if (prevfd > 0) { 489 dup2(prevfd, 0); 490 close(prevfd); 491 } 492 if (pip[1] >= 0) { 493 if (!(prevfd >= 0 && pip[0] == 0)) 494 close(pip[0]); 495 if (pip[1] != 1) { 496 dup2(pip[1], 1); 497 close(pip[1]); 498 } 499 } 500 evaltree(lp->n, EV_EXIT); 501 } 502 if (prevfd >= 0) 503 close(prevfd); 504 prevfd = pip[0]; 505 close(pip[1]); 506 } 507 INTON; 508 if (n->npipe.backgnd == 0) { 509 INTOFF; 510 exitstatus = waitforjob(jp, (int *)NULL); 511 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 512 INTON; 513 } 514} 515 516 517 518/* 519 * Execute a command inside back quotes. If it's a builtin command, we 520 * want to save its output in a block obtained from malloc. Otherwise 521 * we fork off a subprocess and get the output of the command via a pipe. 522 * Should be called with interrupts off. 523 */ 524 525void 526evalbackcmd(union node *n, struct backcmd *result) 527{ 528 int pip[2]; 529 struct job *jp; 530 struct stackmark smark; /* unnecessary */ 531 532 setstackmark(&smark); 533 result->fd = -1; 534 result->buf = NULL; 535 result->nleft = 0; 536 result->jp = NULL; 537 if (n == NULL) { 538 exitstatus = 0; 539 goto out; 540 } 541 if (n->type == NCMD) { 542 exitstatus = oexitstatus; 543 evalcommand(n, EV_BACKCMD, result); 544 } else { 545 exitstatus = 0; 546 if (pipe(pip) < 0) 547 error("Pipe call failed: %s", strerror(errno)); 548 jp = makejob(n, 1); 549 if (forkshell(jp, n, FORK_NOJOB) == 0) { 550 FORCEINTON; 551 close(pip[0]); 552 if (pip[1] != 1) { 553 dup2(pip[1], 1); 554 close(pip[1]); 555 } 556 evaltree(n, EV_EXIT); 557 } 558 close(pip[1]); 559 result->fd = pip[0]; 560 result->jp = jp; 561 } 562out: 563 popstackmark(&smark); 564 TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n", 565 result->fd, result->buf, result->nleft, result->jp)); 566} 567 568 569 570/* 571 * Execute a simple command. 572 */ 573 574STATIC void 575evalcommand(union node *cmd, int flags, struct backcmd *backcmd) 576{ 577 struct stackmark smark; 578 union node *argp; 579 struct arglist arglist; 580 struct arglist varlist; 581 char **argv; 582 int argc; 583 char **envp; 584 int varflag; 585 struct strlist *sp; 586 int mode; 587 int pip[2]; 588 struct cmdentry cmdentry; 589 struct job *jp; 590 struct jmploc jmploc; 591 struct jmploc *savehandler; 592 char *savecmdname; 593 struct shparam saveparam; 594 struct localvar *savelocalvars; 595 struct parsefile *savetopfile; 596 volatile int e; 597 char *lastarg; 598 int realstatus; 599 int do_clearcmdentry; 600 601 /* First expand the arguments. */ 602 TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags)); 603 setstackmark(&smark); 604 arglist.lastp = &arglist.list; 605 varlist.lastp = &varlist.list; 606 varflag = 1; 607 do_clearcmdentry = 0; 608 oexitstatus = exitstatus; 609 exitstatus = 0; 610 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 611 char *p = argp->narg.text; 612 if (varflag && is_name(*p)) { 613 do { 614 p++; 615 } while (is_in_name(*p)); 616 if (*p == '=') { 617 expandarg(argp, &varlist, EXP_VARTILDE); 618 continue; 619 } 620 } 621 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 622 varflag = 0; 623 } 624 *arglist.lastp = NULL; 625 *varlist.lastp = NULL; 626 expredir(cmd->ncmd.redirect); 627 argc = 0; 628 for (sp = arglist.list ; sp ; sp = sp->next) 629 argc++; 630 argv = stalloc(sizeof (char *) * (argc + 1)); 631 632 for (sp = arglist.list ; sp ; sp = sp->next) { 633 TRACE(("evalcommand arg: %s\n", sp->text)); 634 *argv++ = sp->text; 635 } 636 *argv = NULL; 637 lastarg = NULL; 638 if (iflag && funcnest == 0 && argc > 0) 639 lastarg = argv[-1]; 640 argv -= argc; 641 642 /* Print the command if xflag is set. */ 643 if (xflag) { 644 char sep = 0; 645 const char *p; 646 out2str(ps4val()); 647 for (sp = varlist.list ; sp ; sp = sp->next) { 648 if (sep != 0) 649 outc(' ', &errout); 650 p = sp->text; 651 while (*p != '=' && *p != '\0') 652 out2c(*p++); 653 if (*p != '\0') { 654 out2c(*p++); 655 out2qstr(p); 656 } 657 sep = ' '; 658 } 659 for (sp = arglist.list ; sp ; sp = sp->next) { 660 if (sep != 0) 661 outc(' ', &errout); 662 /* Disambiguate command looking like assignment. */ 663 if (sp == arglist.list && 664 strchr(sp->text, '=') != NULL && 665 strchr(sp->text, '\'') == NULL) { 666 out2c('\''); 667 out2str(sp->text); 668 out2c('\''); 669 } else 670 out2qstr(sp->text); 671 sep = ' '; 672 } 673 outc('\n', &errout); 674 flushout(&errout); 675 } 676 677 /* Now locate the command. */ 678 if (argc == 0) { 679 /* Variable assignment(s) without command */ 680 cmdentry.cmdtype = CMDBUILTIN; 681 cmdentry.u.index = BLTINCMD; 682 cmdentry.special = 1; 683 } else { 684 static const char PATH[] = "PATH="; 685 char *path = pathval(); 686 687 /* 688 * Modify the command lookup path, if a PATH= assignment 689 * is present 690 */ 691 for (sp = varlist.list ; sp ; sp = sp->next) 692 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { 693 path = sp->text + sizeof(PATH) - 1; 694 /* 695 * On `PATH=... command`, we need to make 696 * sure that the command isn't using the 697 * non-updated hash table of the outer PATH 698 * setting and we need to make sure that 699 * the hash table isn't filled with items 700 * from the temporary setting. 701 * 702 * It would be better to forbit using and 703 * updating the table while this command 704 * runs, by the command finding mechanism 705 * is heavily integrated with hash handling, 706 * so we just delete the hash before and after 707 * the command runs. Partly deleting like 708 * changepatch() does doesn't seem worth the 709 * bookinging effort, since most such runs add 710 * directories in front of the new PATH. 711 */ 712 clearcmdentry(0); 713 do_clearcmdentry = 1; 714 } 715 716 find_command(argv[0], &cmdentry, 0, path); 717 /* implement the bltin builtin here */ 718 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 719 for (;;) { 720 argv++; 721 if (--argc == 0) 722 break; 723 if ((cmdentry.u.index = find_builtin(*argv, 724 &cmdentry.special)) < 0) { 725 outfmt(&errout, "%s: not found\n", *argv); 726 exitstatus = 127; 727 flushout(&errout); 728 return; 729 } 730 if (cmdentry.u.index != BLTINCMD) 731 break; 732 } 733 } 734 } 735 736 /* Fork off a child process if necessary. */ 737 if (cmd->ncmd.backgnd 738 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) 739 && ((flags & EV_EXIT) == 0 || have_traps())) 740 || ((flags & EV_BACKCMD) != 0 741 && (cmdentry.cmdtype != CMDBUILTIN 742 || cmdentry.u.index == CDCMD 743 || cmdentry.u.index == DOTCMD 744 || cmdentry.u.index == EVALCMD)) 745 || (cmdentry.cmdtype == CMDBUILTIN && 746 cmdentry.u.index == COMMANDCMD)) { 747 jp = makejob(cmd, 1); 748 mode = cmd->ncmd.backgnd; 749 if (flags & EV_BACKCMD) { 750 mode = FORK_NOJOB; 751 if (pipe(pip) < 0) 752 error("Pipe call failed: %s", strerror(errno)); 753 } 754 if (forkshell(jp, cmd, mode) != 0) 755 goto parent; /* at end of routine */ 756 if (flags & EV_BACKCMD) { 757 FORCEINTON; 758 close(pip[0]); 759 if (pip[1] != 1) { 760 dup2(pip[1], 1); 761 close(pip[1]); 762 } 763 } 764 flags |= EV_EXIT; 765 } 766 767 /* This is the child process if a fork occurred. */ 768 /* Execute the command. */ 769 if (cmdentry.cmdtype == CMDFUNCTION) { 770#ifdef DEBUG 771 trputs("Shell function: "); trargs(argv); 772#endif 773 redirect(cmd->ncmd.redirect, REDIR_PUSH); 774 saveparam = shellparam; 775 shellparam.malloc = 0; 776 shellparam.reset = 1; 777 shellparam.nparam = argc - 1; 778 shellparam.p = argv + 1; 779 shellparam.optnext = NULL; 780 INTOFF; 781 savelocalvars = localvars; 782 localvars = NULL; 783 reffunc(cmdentry.u.func); 784 savehandler = handler; 785 if (setjmp(jmploc.loc)) { 786 if (exception == EXSHELLPROC) 787 freeparam(&saveparam); 788 else { 789 freeparam(&shellparam); 790 shellparam = saveparam; 791 } 792 unreffunc(cmdentry.u.func); 793 poplocalvars(); 794 localvars = savelocalvars; 795 handler = savehandler; 796 longjmp(handler->loc, 1); 797 } 798 handler = &jmploc; 799 INTON; 800 for (sp = varlist.list ; sp ; sp = sp->next) 801 mklocal(sp->text); 802 funcnest++; 803 exitstatus = oexitstatus; 804 if (flags & EV_TESTED) 805 evaltree(getfuncnode(cmdentry.u.func), EV_TESTED); 806 else 807 evaltree(getfuncnode(cmdentry.u.func), 0); 808 funcnest--; 809 INTOFF; 810 unreffunc(cmdentry.u.func); 811 poplocalvars(); 812 localvars = savelocalvars; 813 freeparam(&shellparam); 814 shellparam = saveparam; 815 handler = savehandler; 816 popredir(); 817 INTON; 818 if (evalskip == SKIPFUNC) { 819 evalskip = 0; 820 skipcount = 0; 821 } 822 if (flags & EV_EXIT) 823 exitshell(exitstatus); 824 } else if (cmdentry.cmdtype == CMDBUILTIN) { 825#ifdef DEBUG 826 trputs("builtin command: "); trargs(argv); 827#endif 828 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 829 if (flags == EV_BACKCMD) { 830 memout.nleft = 0; 831 memout.nextc = memout.buf; 832 memout.bufsize = 64; 833 mode |= REDIR_BACKQ; 834 } 835 savecmdname = commandname; 836 savetopfile = getcurrentfile(); 837 cmdenviron = varlist.list; 838 e = -1; 839 savehandler = handler; 840 if (setjmp(jmploc.loc)) { 841 e = exception; 842 exitstatus = (e == EXINT)? SIGINT+128 : 2; 843 goto cmddone; 844 } 845 handler = &jmploc; 846 redirect(cmd->ncmd.redirect, mode); 847 if (cmdentry.special) 848 listsetvar(cmdenviron); 849 commandname = argv[0]; 850 argptr = argv + 1; 851 nextopt_optptr = NULL; /* initialize nextopt */ 852 builtin_flags = flags; 853 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 854 flushall(); 855cmddone: 856 cmdenviron = NULL; 857 out1 = &output; 858 out2 = &errout; 859 freestdout(); 860 if (e != EXSHELLPROC) { 861 commandname = savecmdname; 862 if (flags & EV_EXIT) { 863 exitshell(exitstatus); 864 } 865 } 866 handler = savehandler; 867 if (e != -1) { 868 if ((e != EXERROR && e != EXEXEC) 869 || cmdentry.special) 870 exraise(e); 871 popfilesupto(savetopfile); 872 FORCEINTON; 873 } 874 if (cmdentry.u.index != EXECCMD) 875 popredir(); 876 if (flags == EV_BACKCMD) { 877 backcmd->buf = memout.buf; 878 backcmd->nleft = memout.nextc - memout.buf; 879 memout.buf = NULL; 880 } 881 } else { 882#ifdef DEBUG 883 trputs("normal command: "); trargs(argv); 884#endif 885 redirect(cmd->ncmd.redirect, 0); 886 for (sp = varlist.list ; sp ; sp = sp->next) 887 setvareq(sp->text, VEXPORT|VSTACK); 888 envp = environment(); 889 shellexec(argv, envp, pathval(), cmdentry.u.index); 890 /*NOTREACHED*/ 891 } 892 goto out; 893 894parent: /* parent process gets here (if we forked) */ 895 if (mode == 0) { /* argument to fork */ 896 INTOFF; 897 exitstatus = waitforjob(jp, &realstatus); 898 INTON; 899 if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 900 evalskip = SKIPBREAK; 901 skipcount = loopnest; 902 } 903 } else if (mode == 2) { 904 backcmd->fd = pip[0]; 905 close(pip[1]); 906 backcmd->jp = jp; 907 } 908 909out: 910 if (lastarg) 911 setvar("_", lastarg, 0); 912 if (do_clearcmdentry) 913 clearcmdentry(0); 914 popstackmark(&smark); 915} 916 917 918 919/* 920 * Search for a command. This is called before we fork so that the 921 * location of the command will be available in the parent as well as 922 * the child. The check for "goodname" is an overly conservative 923 * check that the name will not be subject to expansion. 924 */ 925 926STATIC void 927prehash(union node *n) 928{ 929 struct cmdentry entry; 930 931 if (n && n->type == NCMD && n->ncmd.args) 932 if (goodname(n->ncmd.args->narg.text)) 933 find_command(n->ncmd.args->narg.text, &entry, 0, 934 pathval()); 935} 936 937 938 939/* 940 * Builtin commands. Builtin commands whose functions are closely 941 * tied to evaluation are implemented here. 942 */ 943 944/* 945 * No command given, or a bltin command with no arguments. 946 */ 947 948int 949bltincmd(int argc __unused, char **argv __unused) 950{ 951 /* 952 * Preserve exitstatus of a previous possible redirection 953 * as POSIX mandates 954 */ 955 return exitstatus; 956} 957 958 959/* 960 * Handle break and continue commands. Break, continue, and return are 961 * all handled by setting the evalskip flag. The evaluation routines 962 * above all check this flag, and if it is set they start skipping 963 * commands rather than executing them. The variable skipcount is 964 * the number of loops to break/continue, or the number of function 965 * levels to return. (The latter is always 1.) It should probably 966 * be an error to break out of more loops than exist, but it isn't 967 * in the standard shell so we don't make it one here. 968 */ 969 970int 971breakcmd(int argc, char **argv) 972{ 973 int n = argc > 1 ? number(argv[1]) : 1; 974 975 if (n > loopnest) 976 n = loopnest; 977 if (n > 0) { 978 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 979 skipcount = n; 980 } 981 return 0; 982} 983 984/* 985 * The `command' command. 986 */ 987int 988commandcmd(int argc, char **argv) 989{ 990 static char stdpath[] = _PATH_STDPATH; 991 struct jmploc loc, *old; 992 struct strlist *sp; 993 char *path; 994 int ch; 995 int cmd = -1; 996 997 for (sp = cmdenviron; sp ; sp = sp->next) 998 setvareq(sp->text, VEXPORT|VSTACK); 999 path = pathval(); 1000 1001 optind = optreset = 1; 1002 opterr = 0; 1003 while ((ch = getopt(argc, argv, "pvV")) != -1) { 1004 switch (ch) { 1005 case 'p': 1006 path = stdpath; 1007 break; 1008 case 'v': 1009 cmd = TYPECMD_SMALLV; 1010 break; 1011 case 'V': 1012 cmd = TYPECMD_BIGV; 1013 break; 1014 case '?': 1015 default: 1016 error("unknown option: -%c", optopt); 1017 } 1018 } 1019 argc -= optind; 1020 argv += optind; 1021 1022 if (cmd != -1) { 1023 if (argc != 1) 1024 error("wrong number of arguments"); 1025 return typecmd_impl(2, argv - 1, cmd); 1026 } 1027 if (argc != 0) { 1028 old = handler; 1029 handler = &loc; 1030 if (setjmp(handler->loc) == 0) 1031 shellexec(argv, environment(), path, 0); 1032 handler = old; 1033 if (exception == EXEXEC) 1034 exit(exerrno); 1035 exraise(exception); 1036 } 1037 1038 /* 1039 * Do nothing successfully if no command was specified; 1040 * ksh also does this. 1041 */ 1042 exit(0); 1043} 1044 1045 1046/* 1047 * The return command. 1048 */ 1049 1050int 1051returncmd(int argc, char **argv) 1052{ 1053 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 1054 1055 if (funcnest) { 1056 evalskip = SKIPFUNC; 1057 skipcount = 1; 1058 } else { 1059 /* skip the rest of the file */ 1060 evalskip = SKIPFILE; 1061 skipcount = 1; 1062 } 1063 return ret; 1064} 1065 1066 1067int 1068falsecmd(int argc __unused, char **argv __unused) 1069{ 1070 return 1; 1071} 1072 1073 1074int 1075truecmd(int argc __unused, char **argv __unused) 1076{ 1077 return 0; 1078} 1079 1080 1081int 1082execcmd(int argc, char **argv) 1083{ 1084 if (argc > 1) { 1085 struct strlist *sp; 1086 1087 iflag = 0; /* exit on error */ 1088 mflag = 0; 1089 optschanged(); 1090 for (sp = cmdenviron; sp ; sp = sp->next) 1091 setvareq(sp->text, VEXPORT|VSTACK); 1092 shellexec(argv + 1, environment(), pathval(), 0); 1093 1094 } 1095 return 0; 1096} 1097 1098 1099int 1100timescmd(int argc __unused, char **argv __unused) 1101{ 1102 struct rusage ru; 1103 long shumins, shsmins, chumins, chsmins; 1104 double shusecs, shssecs, chusecs, chssecs; 1105 1106 if (getrusage(RUSAGE_SELF, &ru) < 0) 1107 return 1; 1108 shumins = ru.ru_utime.tv_sec / 60; 1109 shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1110 shsmins = ru.ru_stime.tv_sec / 60; 1111 shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1112 if (getrusage(RUSAGE_CHILDREN, &ru) < 0) 1113 return 1; 1114 chumins = ru.ru_utime.tv_sec / 60; 1115 chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.; 1116 chsmins = ru.ru_stime.tv_sec / 60; 1117 chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.; 1118 out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins, 1119 shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs); 1120 return 0; 1121} 1122