eval.c revision 45916
1132718Skan/*- 2132718Skan * Copyright (c) 1993 3169689Skan * The Regents of the University of California. All rights reserved. 4132718Skan * 5132718Skan * This code is derived from software contributed to Berkeley by 6132718Skan * Kenneth Almquist. 7132718Skan * 8132718Skan * Redistribution and use in source and binary forms, with or without 9132718Skan * modification, are permitted provided that the following conditions 10132718Skan * are met: 11132718Skan * 1. Redistributions of source code must retain the above copyright 12132718Skan * notice, this list of conditions and the following disclaimer. 13132718Skan * 2. Redistributions in binary form must reproduce the above copyright 14132718Skan * notice, this list of conditions and the following disclaimer in the 15132718Skan * documentation and/or other materials provided with the distribution. 16132718Skan * 3. All advertising materials mentioning features or use of this software 17132718Skan * must display the following acknowledgement: 18132718Skan * This product includes software developed by the University of 19169689Skan * California, Berkeley and its contributors. 20169689Skan * 4. Neither the name of the University nor the names of its contributors 21132718Skan * may be used to endorse or promote products derived from this software 22132718Skan * without specific prior written permission. 23132718Skan * 24132718Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34132718Skan * SUCH DAMAGE. 35132718Skan */ 36146895Skan 37132718Skan#ifndef lint 38146895Skan#if 0 39132718Skanstatic char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 40132718Skan#endif 41132718Skanstatic const char rcsid[] = 42132718Skan "$Id: eval.c,v 1.17 1999/04/03 12:55:51 cracauer Exp $"; 43132718Skan#endif /* not lint */ 44132718Skan 45132718Skan#include <signal.h> 46132718Skan#include <unistd.h> 47132718Skan#include <sys/wait.h> /* For WIFSIGNALED(status) */ 48132718Skan 49132718Skan/* 50132718Skan * Evaluate a command. 51132718Skan */ 52132718Skan 53146895Skan#include "shell.h" 54146895Skan#include "nodes.h" 55146895Skan#include "syntax.h" 56169689Skan#include "expand.h" 57169689Skan#include "parser.h" 58146895Skan#include "jobs.h" 59146895Skan#include "eval.h" 60146895Skan#include "builtins.h" 61146895Skan#include "options.h" 62146895Skan#include "exec.h" 63132718Skan#include "redir.h" 64132718Skan#include "input.h" 65132718Skan#include "output.h" 66132718Skan#include "trap.h" 67132718Skan#include "var.h" 68132718Skan#include "memalloc.h" 69132718Skan#include "error.h" 70132718Skan#include "show.h" 71132718Skan#include "mystring.h" 72132718Skan#ifndef NO_HISTORY 73132718Skan#include "myhistedit.h" 74132718Skan#endif 75169689Skan 76146895Skan 77132718Skan/* flags in argument to evaltree */ 78132718Skan#define EV_EXIT 01 /* exit after evaluating tree */ 79132718Skan#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 80132718Skan#define EV_BACKCMD 04 /* command executing within back quotes */ 81132718Skan 82132718SkanMKINIT int evalskip; /* set if we are skipping commands */ 83132718SkanSTATIC int skipcount; /* number of levels to skip */ 84132718SkanMKINIT int loopnest; /* current loop nesting level */ 85132718Skanint funcnest; /* depth of function calls */ 86132718Skan 87132718Skan 88132718Skanchar *commandname; 89132718Skanstruct strlist *cmdenviron; 90132718Skanint exitstatus; /* exit status of last command */ 91132718Skanint oexitstatus; /* saved exit status */ 92132718Skan 93132718Skan 94132718SkanSTATIC void evalloop __P((union node *)); 95132718SkanSTATIC void evalfor __P((union node *)); 96132718SkanSTATIC void evalcase __P((union node *, int)); 97132718SkanSTATIC void evalsubshell __P((union node *, int)); 98132718SkanSTATIC void expredir __P((union node *)); 99132718SkanSTATIC void evalpipe __P((union node *)); 100132718SkanSTATIC void evalcommand __P((union node *, int, struct backcmd *)); 101132718SkanSTATIC void prehash __P((union node *)); 102132718Skan 103132718Skan 104132718Skan/* 105132718Skan * Called to reset things after an exception. 106132718Skan */ 107132718Skan 108132718Skan#ifdef mkinit 109132718SkanINCLUDE "eval.h" 110132718Skan 111132718SkanRESET { 112146895Skan evalskip = 0; 113146895Skan loopnest = 0; 114146895Skan funcnest = 0; 115146895Skan} 116146895Skan 117146895SkanSHELLPROC { 118169689Skan exitstatus = 0; 119146895Skan} 120146895Skan#endif 121146895Skan 122146895Skan 123146895Skan 124146895Skan/* 125146895Skan * The eval commmand. 126146895Skan */ 127146895Skan 128146895Skanint 129146895Skanevalcmd(argc, argv) 130146895Skan int argc; 131146895Skan char **argv; 132146895Skan{ 133146895Skan char *p; 134146895Skan char *concat; 135146895Skan char **ap; 136146895Skan 137146895Skan if (argc > 1) { 138146895Skan p = argv[1]; 139146895Skan if (argc > 2) { 140146895Skan STARTSTACKSTR(concat); 141146895Skan ap = argv + 2; 142146895Skan for (;;) { 143146895Skan while (*p) 144146895Skan STPUTC(*p++, concat); 145146895Skan if ((p = *ap++) == NULL) 146146895Skan break; 147146895Skan STPUTC(' ', concat); 148146895Skan } 149146895Skan STPUTC('\0', concat); 150146895Skan p = grabstackstr(concat); 151132718Skan } 152132718Skan evalstring(p); 153132718Skan } 154132718Skan return exitstatus; 155132718Skan} 156132718Skan 157132718Skan 158169689Skan/* 159132718Skan * Execute a command or commands contained in a string. 160132718Skan */ 161132718Skan 162132718Skanvoid 163132718Skanevalstring(s) 164132718Skan char *s; 165132718Skan { 166132718Skan union node *n; 167132718Skan struct stackmark smark; 168169689Skan 169132718Skan setstackmark(&smark); 170132718Skan setinputstring(s, 1); 171132718Skan while ((n = parsecmd(0)) != NEOF) { 172132718Skan evaltree(n, 0); 173132718Skan popstackmark(&smark); 174132718Skan } 175132718Skan popfile(); 176132718Skan popstackmark(&smark); 177132718Skan} 178132718Skan 179132718Skan 180132718Skan 181132718Skan/* 182132718Skan * Evaluate a parse tree. The value is left in the global variable 183132718Skan * exitstatus. 184132718Skan */ 185132718Skan 186132718Skanvoid 187132718Skanevaltree(n, flags) 188132718Skan union node *n; 189132718Skan int flags; 190132718Skan{ 191132718Skan if (n == NULL) { 192132718Skan TRACE(("evaltree(NULL) called\n")); 193132718Skan exitstatus = 0; 194132718Skan goto out; 195132718Skan } 196132718Skan#ifndef NO_HISTORY 197132718Skan displayhist = 1; /* show history substitutions done with fc */ 198132718Skan#endif 199132718Skan TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); 200132718Skan switch (n->type) { 201132718Skan case NSEMI: 202132718Skan evaltree(n->nbinary.ch1, 0); 203132718Skan if (evalskip) 204132718Skan goto out; 205132718Skan evaltree(n->nbinary.ch2, flags); 206132718Skan break; 207132718Skan case NAND: 208132718Skan evaltree(n->nbinary.ch1, EV_TESTED); 209132718Skan if (evalskip || exitstatus != 0) { 210132718Skan flags |= EV_TESTED; 211132718Skan goto out; 212146895Skan } 213146895Skan evaltree(n->nbinary.ch2, flags); 214146895Skan break; 215146895Skan case NOR: 216146895Skan evaltree(n->nbinary.ch1, EV_TESTED); 217146895Skan if (evalskip || exitstatus == 0) 218146895Skan goto out; 219146895Skan evaltree(n->nbinary.ch2, flags); 220146895Skan break; 221146895Skan case NREDIR: 222146895Skan expredir(n->nredir.redirect); 223146895Skan redirect(n->nredir.redirect, REDIR_PUSH); 224146895Skan evaltree(n->nredir.n, flags); 225146895Skan popredir(); 226146895Skan break; 227146895Skan case NSUBSHELL: 228146895Skan evalsubshell(n, flags); 229146895Skan break; 230146895Skan case NBACKGND: 231146895Skan evalsubshell(n, flags); 232146895Skan break; 233146895Skan case NIF: { 234146895Skan evaltree(n->nif.test, EV_TESTED); 235146895Skan if (evalskip) 236146895Skan goto out; 237146895Skan if (exitstatus == 0) 238146895Skan evaltree(n->nif.ifpart, flags); 239146895Skan else if (n->nif.elsepart) 240146895Skan evaltree(n->nif.elsepart, flags); 241146895Skan else 242146895Skan exitstatus = 0; 243146895Skan break; 244146895Skan } 245146895Skan case NWHILE: 246146895Skan case NUNTIL: 247146895Skan evalloop(n); 248146895Skan break; 249146895Skan case NFOR: 250146895Skan evalfor(n); 251146895Skan break; 252146895Skan case NCASE: 253146895Skan evalcase(n, flags); 254146895Skan break; 255146895Skan case NDEFUN: 256169689Skan defun(n->narg.text, n->narg.next); 257169689Skan exitstatus = 0; 258146895Skan break; 259146895Skan case NNOT: 260146895Skan evaltree(n->nnot.com, EV_TESTED); 261146895Skan exitstatus = !exitstatus; 262146895Skan break; 263146895Skan 264132718Skan case NPIPE: 265132718Skan evalpipe(n); 266132718Skan break; 267132718Skan case NCMD: 268132718Skan evalcommand(n, flags, (struct backcmd *)NULL); 269132718Skan break; 270132718Skan default: 271132718Skan out1fmt("Node type = %d\n", n->type); 272132718Skan flushout(&output); 273132718Skan break; 274132718Skan } 275132718Skanout: 276169689Skan if (pendingsigs) 277132718Skan dotrap(); 278132718Skan if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 279132718Skan exitshell(exitstatus); 280132718Skan} 281169689Skan 282132718Skan 283132718SkanSTATIC void 284132718Skanevalloop(n) 285132718Skan union node *n; 286132718Skan{ 287132718Skan int status; 288132718Skan 289132718Skan loopnest++; 290169689Skan status = 0; 291169689Skan for (;;) { 292169689Skan evaltree(n->nbinary.ch1, EV_TESTED); 293169689Skan if (evalskip) { 294169689Skanskipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 295169689Skan evalskip = 0; 296169689Skan continue; 297169689Skan } 298169689Skan if (evalskip == SKIPBREAK && --skipcount <= 0) 299169689Skan evalskip = 0; 300169689Skan break; 301169689Skan } 302169689Skan if (n->type == NWHILE) { 303169689Skan if (exitstatus != 0) 304169689Skan break; 305169689Skan } else { 306169689Skan if (exitstatus == 0) 307169689Skan break; 308169689Skan } 309169689Skan evaltree(n->nbinary.ch2, 0); 310132718Skan status = exitstatus; 311132718Skan if (evalskip) 312132718Skan goto skipping; 313169689Skan } 314169689Skan loopnest--; 315132718Skan exitstatus = status; 316132718Skan} 317132718Skan 318132718Skan 319132718Skan 320132718SkanSTATIC void 321132718Skanevalfor(n) 322132718Skan union node *n; 323132718Skan{ 324132718Skan struct arglist arglist; 325132718Skan union node *argp; 326132718Skan struct strlist *sp; 327132718Skan struct stackmark smark; 328132718Skan 329132718Skan setstackmark(&smark); 330132718Skan arglist.lastp = &arglist.list; 331169689Skan for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 332132718Skan oexitstatus = exitstatus; 333169689Skan expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 334132718Skan if (evalskip) 335132718Skan goto out; 336132718Skan } 337132718Skan *arglist.lastp = NULL; 338169689Skan 339132718Skan exitstatus = 0; 340169689Skan loopnest++; 341132718Skan for (sp = arglist.list ; sp ; sp = sp->next) { 342132718Skan setvar(n->nfor.var, sp->text, 0); 343132718Skan evaltree(n->nfor.body, 0); 344132718Skan if (evalskip) { 345132718Skan if (evalskip == SKIPCONT && --skipcount <= 0) { 346132718Skan evalskip = 0; 347132718Skan continue; 348132718Skan } 349132718Skan if (evalskip == SKIPBREAK && --skipcount <= 0) 350169689Skan evalskip = 0; 351169689Skan break; 352169689Skan } 353169689Skan } 354169689Skan loopnest--; 355169689Skanout: 356132718Skan popstackmark(&smark); 357132718Skan} 358132718Skan 359132718Skan 360132718Skan 361132718SkanSTATIC void 362132718Skanevalcase(n, flags) 363132718Skan union node *n; 364132718Skan int flags; 365169689Skan{ 366169689Skan union node *cp; 367169689Skan union node *patp; 368169689Skan struct arglist arglist; 369169689Skan struct stackmark smark; 370169689Skan 371132718Skan setstackmark(&smark); 372132718Skan arglist.lastp = &arglist.list; 373132718Skan oexitstatus = exitstatus; 374132718Skan expandarg(n->ncase.expr, &arglist, EXP_TILDE); 375169689Skan for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 376169689Skan for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 377169689Skan if (casematch(patp, arglist.list->text)) { 378169689Skan if (evalskip == 0) { 379169689Skan evaltree(cp->nclist.body, flags); 380169689Skan } 381132718Skan goto out; 382132718Skan } 383132718Skan } 384132718Skan } 385132718Skanout: 386132718Skan popstackmark(&smark); 387132718Skan} 388132718Skan 389132718Skan 390132718Skan 391132718Skan/* 392132718Skan * Kick off a subshell to evaluate a tree. 393132718Skan */ 394132718Skan 395132718SkanSTATIC void 396132718Skanevalsubshell(n, flags) 397132718Skan union node *n; 398132718Skan int flags; 399132718Skan{ 400132718Skan struct job *jp; 401132718Skan int backgnd = (n->type == NBACKGND); 402132718Skan 403132718Skan expredir(n->nredir.redirect); 404132718Skan jp = makejob(n, 1); 405132718Skan if (forkshell(jp, n, backgnd) == 0) { 406132718Skan if (backgnd) 407132718Skan flags &=~ EV_TESTED; 408132718Skan redirect(n->nredir.redirect, 0); 409132718Skan evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 410132718Skan } 411132718Skan if (! backgnd) { 412132718Skan INTOFF; 413132718Skan exitstatus = waitforjob(jp, (int *)NULL); 414132718Skan INTON; 415132718Skan } 416132718Skan} 417132718Skan 418132718Skan 419132718Skan 420132718Skan/* 421132718Skan * Compute the names of the files in a redirection list. 422132718Skan */ 423132718Skan 424132718SkanSTATIC void 425132718Skanexpredir(n) 426132718Skan union node *n; 427132718Skan{ 428132718Skan union node *redir; 429132718Skan 430132718Skan for (redir = n ; redir ; redir = redir->nfile.next) { 431132718Skan struct arglist fn; 432132718Skan fn.lastp = &fn.list; 433132718Skan oexitstatus = exitstatus; 434132718Skan switch (redir->type) { 435132718Skan case NFROM: 436132718Skan case NTO: 437132718Skan case NAPPEND: 438132718Skan expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 439132718Skan redir->nfile.expfname = fn.list->text; 440132718Skan break; 441132718Skan case NFROMFD: 442132718Skan case NTOFD: 443132718Skan if (redir->ndup.vname) { 444132718Skan expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 445132718Skan fixredir(redir, fn.list->text, 1); 446132718Skan } 447132718Skan break; 448132718Skan } 449132718Skan } 450132718Skan} 451132718Skan 452132718Skan 453132718Skan 454132718Skan/* 455169689Skan * Evaluate a pipeline. All the processes in the pipeline are children 456132718Skan * of the process creating the pipeline. (This differs from some versions 457132718Skan * of the shell, which make the last process in a pipeline the parent 458132718Skan * of all the rest.) 459169689Skan */ 460132718Skan 461132718SkanSTATIC void 462132718Skanevalpipe(n) 463132718Skan union node *n; 464169689Skan{ 465132718Skan struct job *jp; 466132718Skan struct nodelist *lp; 467132718Skan int pipelen; 468132718Skan int prevfd; 469169689Skan int pip[2]; 470132718Skan 471132718Skan TRACE(("evalpipe(0x%lx) called\n", (long)n)); 472132718Skan pipelen = 0; 473132718Skan for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 474169689Skan pipelen++; 475132718Skan INTOFF; 476132718Skan jp = makejob(n, pipelen); 477132718Skan prevfd = -1; 478132718Skan for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 479169689Skan prehash(lp->n); 480132718Skan pip[1] = -1; 481132718Skan if (lp->next) { 482169689Skan if (pipe(pip) < 0) { 483169689Skan close(prevfd); 484169689Skan error("Pipe call failed"); 485169689Skan } 486169689Skan } 487169689Skan if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 488169689Skan INTON; 489132718Skan if (prevfd > 0) { 490132718Skan close(0); 491132718Skan copyfd(prevfd, 0); 492132718Skan close(prevfd); 493132718Skan } 494132718Skan if (pip[1] >= 0) { 495132718Skan close(pip[0]); 496132718Skan if (pip[1] != 1) { 497132718Skan close(1); 498132718Skan copyfd(pip[1], 1); 499132718Skan close(pip[1]); 500132718Skan } 501132718Skan } 502169689Skan evaltree(lp->n, EV_EXIT); 503169689Skan } 504169689Skan if (prevfd >= 0) 505169689Skan close(prevfd); 506169689Skan prevfd = pip[0]; 507169689Skan close(pip[1]); 508169689Skan } 509169689Skan INTON; 510132718Skan if (n->npipe.backgnd == 0) { 511132718Skan INTOFF; 512132718Skan exitstatus = waitforjob(jp, (int *)NULL); 513132718Skan TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 514169689Skan INTON; 515169689Skan } 516169689Skan} 517169689Skan 518169689Skan 519169689Skan 520169689Skan/* 521169689Skan * Execute a command inside back quotes. If it's a builtin command, we 522169689Skan * want to save its output in a block obtained from malloc. Otherwise 523169689Skan * we fork off a subprocess and get the output of the command via a pipe. 524169689Skan * Should be called with interrupts off. 525169689Skan */ 526169689Skan 527169689Skanvoid 528169689Skanevalbackcmd(n, result) 529169689Skan union node *n; 530169689Skan struct backcmd *result; 531169689Skan{ 532169689Skan int pip[2]; 533169689Skan struct job *jp; 534169689Skan struct stackmark smark; /* unnecessary */ 535169689Skan 536169689Skan setstackmark(&smark); 537169689Skan result->fd = -1; 538169689Skan result->buf = NULL; 539169689Skan result->nleft = 0; 540169689Skan result->jp = NULL; 541169689Skan if (n == NULL) { 542169689Skan exitstatus = 0; 543169689Skan goto out; 544169689Skan } 545169689Skan if (n->type == NCMD) { 546169689Skan exitstatus = oexitstatus; 547169689Skan evalcommand(n, EV_BACKCMD, result); 548169689Skan } else { 549169689Skan exitstatus = 0; 550169689Skan if (pipe(pip) < 0) 551169689Skan error("Pipe call failed"); 552169689Skan jp = makejob(n, 1); 553169689Skan if (forkshell(jp, n, FORK_NOJOB) == 0) { 554132718Skan FORCEINTON; 555132718Skan close(pip[0]); 556132718Skan if (pip[1] != 1) { 557132718Skan close(1); 558132718Skan copyfd(pip[1], 1); 559132718Skan close(pip[1]); 560132718Skan } 561132718Skan evaltree(n, EV_EXIT); 562132718Skan } 563132718Skan close(pip[1]); 564132718Skan result->fd = pip[0]; 565132718Skan result->jp = jp; 566132718Skan } 567132718Skanout: 568132718Skan popstackmark(&smark); 569169689Skan TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 570132718Skan result->fd, result->buf, result->nleft, result->jp)); 571132718Skan} 572132718Skan 573132718Skan 574132718Skan 575132718Skan/* 576132718Skan * Execute a simple command. 577132718Skan */ 578132718Skan 579132718SkanSTATIC void 580132718Skanevalcommand(cmd, flags, backcmd) 581132718Skan union node *cmd; 582132718Skan int flags; 583132718Skan struct backcmd *backcmd; 584169689Skan{ 585132718Skan struct stackmark smark; 586132718Skan union node *argp; 587132718Skan struct arglist arglist; 588169689Skan struct arglist varlist; 589132718Skan char **argv; 590169689Skan int argc; 591169689Skan char **envp; 592132718Skan int varflag; 593169689Skan struct strlist *sp; 594169689Skan int mode; 595169689Skan int pip[2]; 596169689Skan struct cmdentry cmdentry; 597169689Skan struct job *jp; 598169689Skan struct jmploc jmploc; 599132718Skan struct jmploc *volatile savehandler; 600169689Skan char *volatile savecmdname; 601169689Skan volatile struct shparam saveparam; 602169689Skan struct localvar *volatile savelocalvars; 603169689Skan volatile int e; 604132718Skan char *lastarg; 605132718Skan int realstatus; 606132718Skan#if __GNUC__ 607132718Skan /* Avoid longjmp clobbering */ 608132718Skan (void) &argv; 609132718Skan (void) &argc; 610132718Skan (void) &lastarg; 611132718Skan (void) &flags; 612132718Skan#endif 613132718Skan 614132718Skan /* First expand the arguments. */ 615132718Skan TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 616132718Skan setstackmark(&smark); 617169689Skan arglist.lastp = &arglist.list; 618132718Skan varlist.lastp = &varlist.list; 619132718Skan varflag = 1; 620132718Skan oexitstatus = exitstatus; 621132718Skan exitstatus = 0; 622132718Skan for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 623132718Skan char *p = argp->narg.text; 624132718Skan if (varflag && is_name(*p)) { 625132718Skan do { 626132718Skan p++; 627132718Skan } while (is_in_name(*p)); 628132718Skan if (*p == '=') { 629132718Skan expandarg(argp, &varlist, EXP_VARTILDE); 630132718Skan continue; 631132718Skan } 632132718Skan } 633132718Skan expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 634132718Skan varflag = 0; 635132718Skan } 636132718Skan *arglist.lastp = NULL; 637132718Skan *varlist.lastp = NULL; 638132718Skan expredir(cmd->ncmd.redirect); 639132718Skan argc = 0; 640132718Skan for (sp = arglist.list ; sp ; sp = sp->next) 641132718Skan argc++; 642132718Skan argv = stalloc(sizeof (char *) * (argc + 1)); 643132718Skan 644132718Skan for (sp = arglist.list ; sp ; sp = sp->next) { 645132718Skan TRACE(("evalcommand arg: %s\n", sp->text)); 646132718Skan *argv++ = sp->text; 647132718Skan } 648132718Skan *argv = NULL; 649132718Skan lastarg = NULL; 650132718Skan if (iflag && funcnest == 0 && argc > 0) 651132718Skan lastarg = argv[-1]; 652132718Skan argv -= argc; 653132718Skan 654132718Skan /* Print the command if xflag is set. */ 655132718Skan if (xflag) { 656132718Skan outc('+', &errout); 657132718Skan for (sp = varlist.list ; sp ; sp = sp->next) { 658132718Skan outc(' ', &errout); 659132718Skan out2str(sp->text); 660132718Skan } 661132718Skan for (sp = arglist.list ; sp ; sp = sp->next) { 662132718Skan outc(' ', &errout); 663132718Skan out2str(sp->text); 664169689Skan } 665169689Skan outc('\n', &errout); 666169689Skan flushout(&errout); 667169689Skan } 668132718Skan 669132718Skan /* Now locate the command. */ 670169689Skan if (argc == 0) { 671169689Skan cmdentry.cmdtype = CMDBUILTIN; 672132718Skan cmdentry.u.index = BLTINCMD; 673169689Skan } else { 674169689Skan static const char PATH[] = "PATH="; 675132718Skan char *path = pathval(); 676169689Skan 677132718Skan /* 678169689Skan * Modify the command lookup path, if a PATH= assignment 679169689Skan * is present 680132718Skan */ 681132718Skan for (sp = varlist.list ; sp ; sp = sp->next) 682169689Skan if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 683169689Skan path = sp->text + sizeof(PATH) - 1; 684169689Skan 685169689Skan find_command(argv[0], &cmdentry, 1, path); 686132718Skan if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 687169689Skan exitstatus = 127; 688169689Skan flushout(&errout); 689169689Skan return; 690132718Skan } 691169689Skan /* implement the bltin builtin here */ 692132718Skan if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 693132718Skan for (;;) { 694132718Skan argv++; 695132718Skan if (--argc == 0) 696132718Skan break; 697132718Skan if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 698132718Skan outfmt(&errout, "%s: not found\n", *argv); 699132718Skan exitstatus = 127; 700132718Skan flushout(&errout); 701132718Skan return; 702132718Skan } 703132718Skan if (cmdentry.u.index != BLTINCMD) 704132718Skan break; 705132718Skan } 706132718Skan } 707132718Skan } 708132718Skan 709132718Skan /* Fork off a child process if necessary. */ 710132718Skan if (cmd->ncmd.backgnd 711132718Skan || (cmdentry.cmdtype == CMDNORMAL 712132718Skan && ((flags & EV_EXIT) == 0 || Tflag)) 713132718Skan || ((flags & EV_BACKCMD) != 0 714132718Skan && (cmdentry.cmdtype != CMDBUILTIN 715132718Skan || cmdentry.u.index == DOTCMD 716132718Skan || cmdentry.u.index == EVALCMD))) { 717132718Skan jp = makejob(cmd, 1); 718132718Skan mode = cmd->ncmd.backgnd; 719132718Skan if (flags & EV_BACKCMD) { 720132718Skan mode = FORK_NOJOB; 721132718Skan if (pipe(pip) < 0) 722132718Skan error("Pipe call failed"); 723132718Skan } 724132718Skan if (forkshell(jp, cmd, mode) != 0) 725132718Skan goto parent; /* at end of routine */ 726132718Skan if (flags & EV_BACKCMD) { 727132718Skan FORCEINTON; 728132718Skan close(pip[0]); 729132718Skan if (pip[1] != 1) { 730132718Skan close(1); 731169689Skan copyfd(pip[1], 1); 732169689Skan close(pip[1]); 733169689Skan } 734169689Skan } 735169689Skan flags |= EV_EXIT; 736169689Skan } 737169689Skan 738169689Skan /* This is the child process if a fork occurred. */ 739169689Skan /* Execute the command. */ 740169689Skan if (cmdentry.cmdtype == CMDFUNCTION) { 741169689Skan#ifdef DEBUG 742169689Skan trputs("Shell function: "); trargs(argv); 743169689Skan#endif 744169689Skan redirect(cmd->ncmd.redirect, REDIR_PUSH); 745169689Skan saveparam = shellparam; 746169689Skan shellparam.malloc = 0; 747169689Skan shellparam.reset = 1; 748169689Skan shellparam.nparam = argc - 1; 749169689Skan shellparam.p = argv + 1; 750169689Skan shellparam.optnext = NULL; 751169689Skan INTOFF; 752169689Skan savelocalvars = localvars; 753169689Skan localvars = NULL; 754169689Skan INTON; 755169689Skan if (setjmp(jmploc.loc)) { 756169689Skan if (exception == EXSHELLPROC) 757169689Skan freeparam((struct shparam *)&saveparam); 758169689Skan else { 759169689Skan freeparam(&shellparam); 760169689Skan shellparam = saveparam; 761169689Skan } 762169689Skan poplocalvars(); 763169689Skan localvars = savelocalvars; 764169689Skan handler = savehandler; 765169689Skan longjmp(handler->loc, 1); 766169689Skan } 767169689Skan savehandler = handler; 768169689Skan handler = &jmploc; 769169689Skan for (sp = varlist.list ; sp ; sp = sp->next) 770169689Skan mklocal(sp->text); 771169689Skan funcnest++; 772169689Skan if (flags & EV_TESTED) 773169689Skan evaltree(cmdentry.u.func, EV_TESTED); 774169689Skan else 775169689Skan evaltree(cmdentry.u.func, 0); 776169689Skan funcnest--; 777169689Skan INTOFF; 778169689Skan poplocalvars(); 779169689Skan localvars = savelocalvars; 780169689Skan freeparam(&shellparam); 781169689Skan shellparam = saveparam; 782169689Skan handler = savehandler; 783132718Skan popredir(); 784132718Skan INTON; 785169689Skan if (evalskip == SKIPFUNC) { 786169689Skan evalskip = 0; 787169689Skan skipcount = 0; 788169689Skan } 789132718Skan if (flags & EV_EXIT) 790132718Skan exitshell(exitstatus); 791132718Skan } else if (cmdentry.cmdtype == CMDBUILTIN) { 792132718Skan#ifdef DEBUG 793132718Skan trputs("builtin command: "); trargs(argv); 794132718Skan#endif 795132718Skan mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 796132718Skan if (flags == EV_BACKCMD) { 797132718Skan memout.nleft = 0; 798132718Skan memout.nextc = memout.buf; 799132718Skan memout.bufsize = 64; 800132718Skan mode |= REDIR_BACKQ; 801132718Skan } 802132718Skan redirect(cmd->ncmd.redirect, mode); 803132718Skan savecmdname = commandname; 804132718Skan cmdenviron = varlist.list; 805132718Skan e = -1; 806132718Skan if (setjmp(jmploc.loc)) { 807132718Skan e = exception; 808132718Skan exitstatus = (e == EXINT)? SIGINT+128 : 2; 809132718Skan goto cmddone; 810132718Skan } 811132718Skan savehandler = handler; 812132718Skan handler = &jmploc; 813132718Skan commandname = argv[0]; 814132718Skan argptr = argv + 1; 815169689Skan optptr = NULL; /* initialize nextopt */ 816169689Skan exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 817169689Skan flushall(); 818169689Skancmddone: 819169689Skan out1 = &output; 820169689Skan out2 = &errout; 821132718Skan freestdout(); 822169689Skan if (e != EXSHELLPROC) { 823169689Skan commandname = savecmdname; 824169689Skan if (flags & EV_EXIT) { 825169689Skan exitshell(exitstatus); 826169689Skan } 827169689Skan } 828169689Skan handler = savehandler; 829169689Skan if (e != -1) { 830169689Skan if ((e != EXERROR && e != EXEXEC) 831132718Skan || cmdentry.u.index == BLTINCMD 832132718Skan || cmdentry.u.index == DOTCMD 833132718Skan || cmdentry.u.index == EVALCMD 834132718Skan#ifndef NO_HISTORY 835132718Skan || cmdentry.u.index == HISTCMD 836132718Skan#endif 837132718Skan || cmdentry.u.index == EXECCMD) 838132718Skan exraise(e); 839132718Skan FORCEINTON; 840132718Skan } 841132718Skan if (cmdentry.u.index != EXECCMD) 842132718Skan popredir(); 843132718Skan if (flags == EV_BACKCMD) { 844132718Skan backcmd->buf = memout.buf; 845132718Skan backcmd->nleft = memout.nextc - memout.buf; 846132718Skan memout.buf = NULL; 847132718Skan } 848132718Skan } else { 849132718Skan#ifdef DEBUG 850132718Skan trputs("normal command: "); trargs(argv); 851132718Skan#endif 852132718Skan clearredir(); 853132718Skan redirect(cmd->ncmd.redirect, 0); 854132718Skan for (sp = varlist.list ; sp ; sp = sp->next) 855132718Skan setvareq(sp->text, VEXPORT|VSTACK); 856132718Skan envp = environment(); 857132718Skan shellexec(argv, envp, pathval(), cmdentry.u.index); 858132718Skan /*NOTREACHED*/ 859132718Skan } 860132718Skan goto out; 861132718Skan 862132718Skanparent: /* parent process gets here (if we forked) */ 863132718Skan if (mode == 0) { /* argument to fork */ 864132718Skan INTOFF; 865132718Skan exitstatus = waitforjob(jp, &realstatus); 866132718Skan INTON; 867132718Skan if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { 868132718Skan evalskip = SKIPBREAK; 869132718Skan skipcount = loopnest; 870132718Skan } 871132718Skan } else if (mode == 2) { 872132718Skan backcmd->fd = pip[0]; 873132718Skan close(pip[1]); 874132718Skan backcmd->jp = jp; 875132718Skan } 876132718Skan 877132718Skanout: 878169689Skan if (lastarg) 879169689Skan setvar("_", lastarg, 0); 880169689Skan popstackmark(&smark); 881132718Skan} 882169689Skan 883169689Skan 884169689Skan 885169689Skan/* 886169689Skan * Search for a command. This is called before we fork so that the 887169689Skan * location of the command will be available in the parent as well as 888169689Skan * the child. The check for "goodname" is an overly conservative 889169689Skan * check that the name will not be subject to expansion. 890169689Skan */ 891169689Skan 892169689SkanSTATIC void 893169689Skanprehash(n) 894169689Skan union node *n; 895169689Skan{ 896132718Skan struct cmdentry entry; 897132718Skan 898132718Skan if (n->type == NCMD && n->ncmd.args) 899132718Skan if (goodname(n->ncmd.args->narg.text)) 900132718Skan find_command(n->ncmd.args->narg.text, &entry, 0, 901132718Skan pathval()); 902132718Skan} 903132718Skan 904132718Skan 905169689Skan 906169689Skan/* 907169689Skan * Builtin commands. Builtin commands whose functions are closely 908169689Skan * tied to evaluation are implemented here. 909169689Skan */ 910169689Skan 911169689Skan/* 912169689Skan * No command given, or a bltin command with no arguments. Set the 913169689Skan * specified variables. 914132718Skan */ 915169689Skan 916169689Skanint 917169689Skanbltincmd(argc, argv) 918169689Skan int argc __unused; 919169689Skan char **argv __unused; 920169689Skan{ 921169689Skan listsetvar(cmdenviron); 922169689Skan /* 923169689Skan * Preserve exitstatus of a previous possible redirection 924169689Skan * as POSIX mandates 925169689Skan */ 926169689Skan return exitstatus; 927169689Skan} 928169689Skan 929169689Skan 930169689Skan/* 931169689Skan * Handle break and continue commands. Break, continue, and return are 932169689Skan * all handled by setting the evalskip flag. The evaluation routines 933169689Skan * above all check this flag, and if it is set they start skipping 934169689Skan * commands rather than executing them. The variable skipcount is 935169689Skan * the number of loops to break/continue, or the number of function 936169689Skan * levels to return. (The latter is always 1.) It should probably 937169689Skan * be an error to break out of more loops than exist, but it isn't 938169689Skan * in the standard shell so we don't make it one here. 939169689Skan */ 940169689Skan 941169689Skanint 942169689Skanbreakcmd(argc, argv) 943169689Skan int argc; 944169689Skan char **argv; 945169689Skan{ 946169689Skan int n = argc > 1 ? number(argv[1]) : 1; 947169689Skan 948169689Skan if (n > loopnest) 949169689Skan n = loopnest; 950169689Skan if (n > 0) { 951169689Skan evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 952169689Skan skipcount = n; 953169689Skan } 954169689Skan return 0; 955169689Skan} 956169689Skan 957169689Skan 958169689Skan/* 959169689Skan * The return command. 960169689Skan */ 961169689Skan 962169689Skanint 963169689Skanreturncmd(argc, argv) 964169689Skan int argc; 965169689Skan char **argv; 966169689Skan{ 967169689Skan int ret = argc > 1 ? number(argv[1]) : oexitstatus; 968132718Skan 969132718Skan if (funcnest) { 970132718Skan evalskip = SKIPFUNC; 971132718Skan skipcount = 1; 972132718Skan } else { 973132718Skan /* skip the rest of the file */ 974132718Skan evalskip = SKIPFILE; 975132718Skan skipcount = 1; 976132718Skan } 977132718Skan return ret; 978132718Skan} 979132718Skan 980132718Skan 981132718Skanint 982132718Skanfalsecmd(argc, argv) 983132718Skan int argc __unused; 984132718Skan char **argv __unused; 985132718Skan{ 986132718Skan return 1; 987132718Skan} 988132718Skan 989132718Skan 990132718Skanint 991132718Skantruecmd(argc, argv) 992132718Skan int argc __unused; 993132718Skan char **argv __unused; 994132718Skan{ 995132718Skan return 0; 996169689Skan} 997132718Skan 998132718Skan 999132718Skanint 1000169689Skanexeccmd(argc, argv) 1001132718Skan int argc; 1002132718Skan char **argv; 1003132718Skan{ 1004132718Skan if (argc > 1) { 1005132718Skan struct strlist *sp; 1006132718Skan 1007132718Skan iflag = 0; /* exit on error */ 1008132718Skan mflag = 0; 1009132718Skan optschanged(); 1010132718Skan for (sp = cmdenviron; sp ; sp = sp->next) 1011132718Skan setvareq(sp->text, VEXPORT|VSTACK); 1012132718Skan shellexec(argv + 1, environment(), pathval(), 0); 1013132718Skan 1014132718Skan } 1015132718Skan return 0; 1016132718Skan} 1017169689Skan