master xplshn/aruu / cmd / posix / sh / eval.c
   1/*-
   2 * SPDX-License-Identifier: BSD-3-Clause
   3 *
   4 * Copyright (c) 1993
   5 *	The Regents of the University of California.  All rights reserved.
   6 *
   7 * This code is derived from software contributed to Berkeley by
   8 * Kenneth Almquist.
   9 *
  10 * Redistribution and use in source and binary forms, with or without
  11 * modification, are permitted provided that the following conditions
  12 * are met:
  13 * 1. Redistributions of source code must retain the above copyright
  14 *    notice, this list of conditions and the following disclaimer.
  15 * 2. Redistributions in binary form must reproduce the above copyright
  16 *    notice, this list of conditions and the following disclaimer in the
  17 *    documentation and/or other materials provided with the distribution.
  18 * 3. Neither the name of the University nor the names of its contributors
  19 *    may be used to endorse or promote products derived from this software
  20 *    without specific prior written permission.
  21 *
  22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32 * SUCH DAMAGE.
  33 */
  34
  35#include <paths.h>
  36#include <signal.h>
  37#include <stdlib.h>
  38#include <unistd.h>
  39#include <sys/resource.h>
  40#include <errno.h>
  41
  42/*
  43 * Evaluate a command.
  44 */
  45
  46#include "shell.h"
  47#include "nodes.h"
  48#include "syntax.h"
  49#include "expand.h"
  50#include "parser.h"
  51#include "jobs.h"
  52#include "eval.h"
  53#include "builtins.h"
  54#include "options.h"
  55#include "exec.h"
  56#include "redir.h"
  57#include "input.h"
  58#include "output.h"
  59#include "trap.h"
  60#include "var.h"
  61#include "memalloc.h"
  62#include "error.h"
  63#include "show.h"
  64#include "mystring.h"
  65#ifndef NO_HISTORY
  66#include "lineedit.h"
  67#endif
  68
  69
  70int evalskip;			/* set if we are skipping commands */
  71int skipcount;			/* number of levels to skip */
  72static int loopnest;		/* current loop nesting level */
  73int funcnest;			/* depth of function calls */
  74static int builtin_flags;	/* evalcommand flags for builtins */
  75
  76
  77char *commandname;
  78struct arglist *cmdenviron;
  79int exitstatus;			/* exit status of last command */
  80int oexitstatus;		/* saved exit status */
  81
  82
  83static void evalloop(union node *, int);
  84static void evalfor(union node *, int);
  85static union node *evalcase(union node *);
  86static void evalsubshell(union node *, int);
  87static void evalredir(union node *, int);
  88static void exphere(union node *, struct arglist *);
  89static void expredir(union node *);
  90static void evalpipe(union node *);
  91static int is_valid_fast_cmdsubst(union node *n);
  92static void evalcommand(union node *, int, struct backcmd *);
  93static void prehash(union node *);
  94
  95
  96/*
  97 * Called to reset things after an exception.
  98 */
  99
 100void
 101reseteval(void)
 102{
 103	evalskip = 0;
 104	loopnest = 0;
 105}
 106
 107
 108/*
 109 * The eval command.
 110 */
 111
 112int
 113evalcmd(int argc, char **argv)
 114{
 115        char *p;
 116        char *concat;
 117        char **ap;
 118
 119        if (argc > 1) {
 120                p = argv[1];
 121                if (argc > 2) {
 122                        STARTSTACKSTR(concat);
 123                        ap = argv + 2;
 124                        for (;;) {
 125                                STPUTS(p, concat);
 126                                if ((p = *ap++) == NULL)
 127                                        break;
 128                                STPUTC(' ', concat);
 129                        }
 130                        STPUTC('\0', concat);
 131                        p = grabstackstr(concat);
 132                }
 133                evalstring(p, builtin_flags);
 134        } else
 135                exitstatus = 0;
 136        return exitstatus;
 137}
 138
 139
 140/*
 141 * Execute a command or commands contained in a string.
 142 */
 143
 144void
 145evalstring(const char *s, int flags)
 146{
 147	union node *n;
 148	struct stackmark smark;
 149	int flags_exit;
 150	int any;
 151
 152	flags_exit = flags & EV_EXIT;
 153	flags &= ~EV_EXIT;
 154	any = 0;
 155	setstackmark(&smark);
 156	setinputstring(s);
 157	while ((n = parsecmd(0)) != NEOF) {
 158		if (n != NULL && !nflag) {
 159			if (flags_exit && preadateof())
 160				evaltree(n, flags | EV_EXIT);
 161			else
 162				evaltree(n, flags);
 163			any = 1;
 164			if (evalskip)
 165				break;
 166		}
 167		popstackmark(&smark);
 168		setstackmark(&smark);
 169	}
 170	popfile();
 171	popstackmark(&smark);
 172	if (!any)
 173		exitstatus = 0;
 174	if (flags_exit)
 175		exraise(EXEXIT);
 176}
 177
 178
 179/*
 180 * Evaluate a parse tree.  The value is left in the global variable
 181 * exitstatus.
 182 */
 183
 184void
 185evaltree(union node *n, int flags)
 186{
 187	int do_etest;
 188	union node *next;
 189	struct stackmark smark;
 190
 191	setstackmark(&smark);
 192	do_etest = 0;
 193	if (n == NULL) {
 194		TRACE(("evaltree(NULL) called\n"));
 195		exitstatus = 0;
 196		goto out;
 197	}
 198	do {
 199		next = NULL;
 200#ifndef NO_HISTORY
 201		displayhist = 1;	/* show history substitutions done with fc */
 202#endif
 203		TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
 204		switch (n->type) {
 205		case NSEMI:
 206			evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
 207			if (evalskip)
 208				goto out;
 209			next = n->nbinary.ch2;
 210			break;
 211		case NAND:
 212			evaltree(n->nbinary.ch1, EV_TESTED);
 213			if (evalskip || exitstatus != 0) {
 214				goto out;
 215			}
 216			next = n->nbinary.ch2;
 217			break;
 218		case NOR:
 219			evaltree(n->nbinary.ch1, EV_TESTED);
 220			if (evalskip || exitstatus == 0)
 221				goto out;
 222			next = n->nbinary.ch2;
 223			break;
 224		case NREDIR:
 225			evalredir(n, flags);
 226			break;
 227		case NSUBSHELL:
 228			evalsubshell(n, flags);
 229			do_etest = !(flags & EV_TESTED);
 230			break;
 231		case NBACKGND:
 232			evalsubshell(n, flags);
 233			break;
 234		case NIF: {
 235			evaltree(n->nif.test, EV_TESTED);
 236			if (evalskip)
 237				goto out;
 238			if (exitstatus == 0)
 239				next = n->nif.ifpart;
 240			else if (n->nif.elsepart)
 241				next = n->nif.elsepart;
 242			else
 243				exitstatus = 0;
 244			break;
 245		}
 246		case NWHILE:
 247		case NUNTIL:
 248			evalloop(n, flags & ~EV_EXIT);
 249			break;
 250		case NFOR:
 251			evalfor(n, flags & ~EV_EXIT);
 252			break;
 253		case NCASE:
 254			next = evalcase(n);
 255			break;
 256		case NCLIST:
 257			next = n->nclist.body;
 258			break;
 259		case NCLISTFALLTHRU:
 260			if (n->nclist.body) {
 261				evaltree(n->nclist.body, flags & ~EV_EXIT);
 262				if (evalskip)
 263					goto out;
 264			}
 265			next = n->nclist.next;
 266			break;
 267		case NDEFUN:
 268			defun(n->narg.text, n->narg.next);
 269			exitstatus = 0;
 270			break;
 271		case NNOT:
 272			evaltree(n->nnot.com, EV_TESTED);
 273			if (evalskip)
 274				goto out;
 275			exitstatus = !exitstatus;
 276			break;
 277
 278		case NPIPE:
 279			evalpipe(n);
 280			do_etest = !(flags & EV_TESTED);
 281			break;
 282		case NCMD:
 283			evalcommand(n, flags, (struct backcmd *)NULL);
 284			do_etest = !(flags & EV_TESTED);
 285			break;
 286		default:
 287			out1fmt("Node type = %d\n", n->type);
 288			flushout(&output);
 289			break;
 290		}
 291		n = next;
 292		popstackmark(&smark);
 293		setstackmark(&smark);
 294	} while (n != NULL);
 295out:
 296	popstackmark(&smark);
 297	if (pendingsig)
 298		dotrap();
 299	if (eflag && exitstatus != 0 && do_etest)
 300		exitshell(exitstatus);
 301	if (flags & EV_EXIT)
 302		exraise(EXEXIT);
 303}
 304
 305
 306static void
 307evalloop(union node *n, int flags)
 308{
 309	int status;
 310
 311	loopnest++;
 312	status = 0;
 313	for (;;) {
 314		if (!evalskip)
 315			evaltree(n->nbinary.ch1, EV_TESTED);
 316		if (evalskip) {
 317			if (evalskip == SKIPCONT && --skipcount <= 0) {
 318				evalskip = 0;
 319				continue;
 320			}
 321			if (evalskip == SKIPBREAK && --skipcount <= 0)
 322				evalskip = 0;
 323			if (evalskip == SKIPRETURN)
 324				status = exitstatus;
 325			break;
 326		}
 327		if (n->type == NWHILE) {
 328			if (exitstatus != 0)
 329				break;
 330		} else {
 331			if (exitstatus == 0)
 332				break;
 333		}
 334		evaltree(n->nbinary.ch2, flags);
 335		status = exitstatus;
 336	}
 337	loopnest--;
 338	exitstatus = status;
 339}
 340
 341
 342
 343static void
 344evalfor(union node *n, int flags)
 345{
 346	struct arglist arglist;
 347	union node *argp;
 348	int i;
 349	int status;
 350
 351	emptyarglist(&arglist);
 352	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
 353		oexitstatus = exitstatus;
 354		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
 355	}
 356
 357	loopnest++;
 358	status = 0;
 359	for (i = 0; i < arglist.count; i++) {
 360		setvar(n->nfor.var, arglist.args[i], 0);
 361		evaltree(n->nfor.body, flags);
 362		status = exitstatus;
 363		if (evalskip) {
 364			if (evalskip == SKIPCONT && --skipcount <= 0) {
 365				evalskip = 0;
 366				continue;
 367			}
 368			if (evalskip == SKIPBREAK && --skipcount <= 0)
 369				evalskip = 0;
 370			break;
 371		}
 372	}
 373	loopnest--;
 374	exitstatus = status;
 375}
 376
 377
 378/*
 379 * Evaluate a case statement, returning the selected tree.
 380 *
 381 * The exit status needs care to get right.
 382 */
 383
 384static union node *
 385evalcase(union node *n)
 386{
 387	union node *cp;
 388	union node *patp;
 389	struct arglist arglist;
 390
 391	emptyarglist(&arglist);
 392	oexitstatus = exitstatus;
 393	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
 394	for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
 395		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
 396			if (casematch(patp, arglist.args[0])) {
 397				while (cp->nclist.next &&
 398				    cp->type == NCLISTFALLTHRU &&
 399				    cp->nclist.body == NULL)
 400					cp = cp->nclist.next;
 401				if (cp->nclist.next &&
 402				    cp->type == NCLISTFALLTHRU)
 403					return (cp);
 404				if (cp->nclist.body == NULL)
 405					exitstatus = 0;
 406				return (cp->nclist.body);
 407			}
 408		}
 409	}
 410	exitstatus = 0;
 411	return (NULL);
 412}
 413
 414
 415
 416/*
 417 * Kick off a subshell to evaluate a tree.
 418 */
 419
 420static void
 421evalsubshell(union node *n, int flags)
 422{
 423	struct job *jp;
 424	int backgnd = (n->type == NBACKGND);
 425
 426	oexitstatus = exitstatus;
 427	expredir(n->nredir.redirect);
 428	if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
 429			forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
 430		if (backgnd)
 431			flags &=~ EV_TESTED;
 432		redirect(n->nredir.redirect, 0);
 433		evaltree(n->nredir.n, flags | EV_EXIT);	/* never returns */
 434	} else if (! backgnd) {
 435		INTOFF;
 436		exitstatus = waitforjob(jp, (int *)NULL);
 437		INTON;
 438	} else
 439		exitstatus = 0;
 440}
 441
 442
 443/*
 444 * Evaluate a redirected compound command.
 445 */
 446
 447static void
 448evalredir(union node *n, int flags)
 449{
 450	struct jmploc jmploc;
 451	struct jmploc *savehandler;
 452	volatile int in_redirect = 1;
 453
 454	oexitstatus = exitstatus;
 455	expredir(n->nredir.redirect);
 456	savehandler = handler;
 457	if (setjmp(jmploc.loc)) {
 458		int e;
 459
 460		handler = savehandler;
 461		e = exception;
 462		popredir();
 463		if (e == EXERROR && in_redirect) {
 464			FORCEINTON;
 465			return;
 466		}
 467		longjmp(handler->loc, 1);
 468	} else {
 469		INTOFF;
 470		handler = &jmploc;
 471		redirect(n->nredir.redirect, REDIR_PUSH);
 472		in_redirect = 0;
 473		INTON;
 474		evaltree(n->nredir.n, flags);
 475	}
 476	INTOFF;
 477	handler = savehandler;
 478	popredir();
 479	INTON;
 480}
 481
 482
 483static void
 484exphere(union node *redir, struct arglist *fn)
 485{
 486	struct jmploc jmploc;
 487	struct jmploc *savehandler;
 488	struct localvar *savelocalvars;
 489	int need_longjmp = 0;
 490	unsigned char saveoptreset;
 491
 492	redir->nhere.expdoc = "";
 493	savelocalvars = localvars;
 494	localvars = NULL;
 495	saveoptreset = shellparam.reset;
 496	forcelocal++;
 497	savehandler = handler;
 498	if (setjmp(jmploc.loc))
 499		need_longjmp = exception != EXERROR;
 500	else {
 501		handler = &jmploc;
 502		expandarg(redir->nhere.doc, fn, 0);
 503		redir->nhere.expdoc = fn->args[0];
 504		INTOFF;
 505	}
 506	handler = savehandler;
 507	forcelocal--;
 508	poplocalvars();
 509	localvars = savelocalvars;
 510	shellparam.reset = saveoptreset;
 511	if (need_longjmp)
 512		longjmp(handler->loc, 1);
 513	INTON;
 514}
 515
 516
 517/*
 518 * Compute the names of the files in a redirection list.
 519 */
 520
 521static void
 522expredir(union node *n)
 523{
 524	union node *redir;
 525
 526	for (redir = n ; redir ; redir = redir->nfile.next) {
 527		struct arglist fn;
 528		emptyarglist(&fn);
 529		switch (redir->type) {
 530		case NFROM:
 531		case NTO:
 532		case NFROMTO:
 533		case NAPPEND:
 534		case NCLOBBER:
 535			expandarg(redir->nfile.fname, &fn, EXP_TILDE);
 536			redir->nfile.expfname = fn.args[0];
 537			break;
 538		case NFROMFD:
 539		case NTOFD:
 540			if (redir->ndup.vname) {
 541				expandarg(redir->ndup.vname, &fn, EXP_TILDE);
 542				fixredir(redir, fn.args[0], 1);
 543			}
 544			break;
 545		case NXHERE:
 546			exphere(redir, &fn);
 547			break;
 548		}
 549	}
 550}
 551
 552
 553
 554/*
 555 * Evaluate a pipeline.  All the processes in the pipeline are children
 556 * of the process creating the pipeline.  (This differs from some versions
 557 * of the shell, which make the last process in a pipeline the parent
 558 * of all the rest.)
 559 */
 560
 561static void
 562evalpipe(union node *n)
 563{
 564	struct job *jp;
 565	struct nodelist *lp;
 566	int pipelen;
 567	int prevfd;
 568	int pip[2];
 569
 570	TRACE(("evalpipe(%p) called\n", (void *)n));
 571	pipelen = 0;
 572	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
 573		pipelen++;
 574	INTOFF;
 575	jp = makejob(n, pipelen);
 576	prevfd = -1;
 577	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
 578		prehash(lp->n);
 579		pip[1] = -1;
 580		if (lp->next) {
 581			if (pipe(pip) < 0) {
 582				if (prevfd >= 0)
 583					close(prevfd);
 584				error("Pipe call failed: %s", strerror(errno));
 585			}
 586		}
 587		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
 588			INTON;
 589			if (prevfd > 0) {
 590				dup2(prevfd, 0);
 591				close(prevfd);
 592			}
 593			if (pip[1] >= 0) {
 594				if (!(prevfd >= 0 && pip[0] == 0))
 595					close(pip[0]);
 596				if (pip[1] != 1) {
 597					dup2(pip[1], 1);
 598					close(pip[1]);
 599				}
 600			}
 601			evaltree(lp->n, EV_EXIT);
 602		}
 603		if (prevfd >= 0)
 604			close(prevfd);
 605		prevfd = pip[0];
 606		if (pip[1] != -1)
 607			close(pip[1]);
 608	}
 609	INTON;
 610	if (n->npipe.backgnd == 0) {
 611		INTOFF;
 612		exitstatus = waitforjob(jp, (int *)NULL);
 613		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
 614		INTON;
 615	} else
 616		exitstatus = 0;
 617}
 618
 619
 620
 621static int
 622is_valid_fast_cmdsubst(union node *n)
 623{
 624
 625	return (n->type == NCMD);
 626}
 627
 628/*
 629 * Execute a command inside back quotes.  If it's a builtin command, we
 630 * want to save its output in a block obtained from malloc.  Otherwise
 631 * we fork off a subprocess and get the output of the command via a pipe.
 632 * Should be called with interrupts off.
 633 */
 634
 635void
 636evalbackcmd(union node *n, struct backcmd *result)
 637{
 638	int pip[2];
 639	struct job *jp;
 640	struct stackmark smark;
 641	struct jmploc jmploc;
 642	struct jmploc *savehandler;
 643	struct localvar *savelocalvars;
 644	unsigned char saveoptreset;
 645
 646	result->fd = -1;
 647	result->buf = NULL;
 648	result->nleft = 0;
 649	result->jp = NULL;
 650	if (n == NULL) {
 651		exitstatus = 0;
 652		return;
 653	}
 654	setstackmark(&smark);
 655	exitstatus = oexitstatus;
 656	if (is_valid_fast_cmdsubst(n)) {
 657		savelocalvars = localvars;
 658		localvars = NULL;
 659		saveoptreset = shellparam.reset;
 660		forcelocal++;
 661		savehandler = handler;
 662		if (setjmp(jmploc.loc)) {
 663			if (exception == EXERROR)
 664				/* nothing */;
 665			else if (exception != 0) {
 666				handler = savehandler;
 667				forcelocal--;
 668				poplocalvars();
 669				localvars = savelocalvars;
 670				shellparam.reset = saveoptreset;
 671				longjmp(handler->loc, 1);
 672			}
 673		} else {
 674			handler = &jmploc;
 675			evalcommand(n, EV_BACKCMD, result);
 676		}
 677		handler = savehandler;
 678		forcelocal--;
 679		poplocalvars();
 680		localvars = savelocalvars;
 681		shellparam.reset = saveoptreset;
 682	} else {
 683		if (pipe(pip) < 0)
 684			error("Pipe call failed: %s", strerror(errno));
 685		jp = makejob(n, 1);
 686		if (forkshell(jp, n, FORK_NOJOB) == 0) {
 687			FORCEINTON;
 688			close(pip[0]);
 689			if (pip[1] != 1) {
 690				dup2(pip[1], 1);
 691				close(pip[1]);
 692			}
 693			evaltree(n, EV_EXIT);
 694		}
 695		close(pip[1]);
 696		result->fd = pip[0];
 697		result->jp = jp;
 698	}
 699	popstackmark(&smark);
 700	TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
 701		result->fd, result->buf, result->nleft, result->jp));
 702}
 703
 704static int
 705mustexpandto(const char *argtext, const char *mask)
 706{
 707	for (;;) {
 708		if (*argtext == CTLQUOTEMARK || *argtext == CTLQUOTEEND) {
 709			argtext++;
 710			continue;
 711		}
 712		if (*argtext == CTLESC)
 713			argtext++;
 714		else if (BASESYNTAX[(int)*argtext] == CCTL)
 715			return (0);
 716		if (*argtext != *mask)
 717			return (0);
 718		if (*argtext == '\0')
 719			return (1);
 720		argtext++;
 721		mask++;
 722	}
 723}
 724
 725static int
 726isdeclarationcmd(struct narg *arg)
 727{
 728	int have_command = 0;
 729
 730	if (arg == NULL)
 731		return (0);
 732	while (mustexpandto(arg->text, "command")) {
 733		have_command = 1;
 734		arg = &arg->next->narg;
 735		if (arg == NULL)
 736			return (0);
 737		/*
 738		 * To also allow "command -p" and "command --" as part of
 739		 * a declaration command, add code here.
 740		 * We do not do this, as ksh does not do it either and it
 741		 * is not required by POSIX.
 742		 */
 743	}
 744	return (mustexpandto(arg->text, "export") ||
 745	    mustexpandto(arg->text, "readonly") ||
 746	    (mustexpandto(arg->text, "local") &&
 747		(have_command || !isfunc("local"))));
 748}
 749
 750static void
 751xtracecommand(struct arglist *varlist, int argc, char **argv)
 752{
 753	char sep = 0;
 754	const char *text, *p, *ps4;
 755	int i;
 756
 757	ps4 = expandstr(ps4val());
 758	out2str(ps4 != NULL ? ps4 : ps4val());
 759	for (i = 0; i < varlist->count; i++) {
 760		text = varlist->args[i];
 761		if (sep != 0)
 762			out2c(' ');
 763		p = strchr(text, '=');
 764		if (p != NULL) {
 765			p++;
 766			outbin(text, p - text, out2);
 767			out2qstr(p);
 768		} else
 769			out2qstr(text);
 770		sep = ' ';
 771	}
 772	for (i = 0; i < argc; i++) {
 773		text = argv[i];
 774		if (sep != 0)
 775			out2c(' ');
 776		out2qstr(text);
 777		sep = ' ';
 778	}
 779	out2c('\n');
 780	flushout(&errout);
 781}
 782
 783/*
 784 * Check if a builtin can safely be executed in the same process,
 785 * even though it should be in a subshell (command substitution).
 786 * Note that jobid, jobs, times and trap can show information not
 787 * available in a child process; this is deliberate.
 788 * The arguments should already have been expanded.
 789 */
 790static int
 791safe_builtin(int idx, int argc, char **argv)
 792{
 793	/* Generated from builtins.def. */
 794	if (safe_builtin_always(idx))
 795		return (1);
 796	if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
 797	    idx == UMASKCMD)
 798		return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
 799	if (idx == SETCMD)
 800		return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
 801		    argv[1][0] == '+') && argv[1][1] == 'o' &&
 802		    argv[1][2] == '\0'));
 803	return (0);
 804}
 805
 806/*
 807 * Perform redirections, then execute a simple command with vfork.
 808 * This cannot be used for command substitutions for two reasons:
 809 * - Redirections might cause the error message for later redirections or for
 810 *   an unknown command to be sent to the pipe (to be substituted), and this
 811 *   might cause a deadlock if the message is too long.
 812 * - The assignment of the pipe needs to come before instead of after the
 813 *   redirections.
 814 */
 815static int
 816redirected_vforkexecshell(struct job *jp, union node *redir, char **argv,
 817    char **envp, const char *path, int idx)
 818{
 819	struct jmploc jmploc;
 820	struct jmploc *savehandler;
 821	volatile int in_redirect = 1;
 822
 823	savehandler = handler;
 824	if (setjmp(jmploc.loc)) {
 825		int e;
 826
 827		handler = savehandler;
 828		e = exception;
 829		popredir();
 830		if (e == EXERROR && in_redirect) {
 831			FORCEINTON;
 832			return 0;
 833		}
 834		longjmp(handler->loc, 1);
 835	} else {
 836		INTOFF;
 837		handler = &jmploc;
 838		redirect(redir, REDIR_PUSH);
 839		in_redirect = 0;
 840		INTON;
 841		vforkexecshell(jp, argv, envp, path, idx, NULL);
 842	}
 843	INTOFF;
 844	handler = savehandler;
 845	popredir();
 846	INTON;
 847	return 1;
 848}
 849
 850/*
 851 * Execute a simple command.
 852 * Note: This may or may not return if (flags & EV_EXIT).
 853 */
 854
 855static void
 856evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
 857{
 858	union node *argp;
 859	struct arglist arglist;
 860	struct arglist varlist;
 861	char **argv;
 862	int argc;
 863	char **envp;
 864	int varflag;
 865	int mode;
 866	int pip[2];
 867	struct cmdentry cmdentry;
 868	struct job *jp;
 869	struct jmploc jmploc;
 870	struct jmploc *savehandler;
 871	char *savecmdname;
 872	struct shparam saveparam;
 873	struct localvar *savelocalvars;
 874	struct parsefile *savetopfile;
 875	volatile int e;
 876	char *lastarg;
 877	int signaled;
 878	int do_clearcmdentry;
 879	const char *path = pathval();
 880	int i;
 881
 882	/* First expand the arguments. */
 883	TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
 884	emptyarglist(&arglist);
 885	emptyarglist(&varlist);
 886	varflag = 1;
 887	jp = NULL;
 888	do_clearcmdentry = 0;
 889	oexitstatus = exitstatus;
 890	exitstatus = 0;
 891	/* Add one slot at the beginning for tryexec(). */
 892	appendarglist(&arglist, nullstr);
 893	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
 894		if (varflag && isassignment(argp->narg.text)) {
 895			expandarg(argp, varflag == 1 ? &varlist : &arglist,
 896			    EXP_VARTILDE);
 897			continue;
 898		} else if (varflag == 1)
 899			varflag = isdeclarationcmd(&argp->narg) ? 2 : 0;
 900		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
 901	}
 902	appendarglist(&arglist, nullstr);
 903	expredir(cmd->ncmd.redirect);
 904	argc = arglist.count - 2;
 905	argv = &arglist.args[1];
 906
 907	argv[argc] = NULL;
 908	lastarg = NULL;
 909	if (iflag && funcnest == 0 && argc > 0)
 910		lastarg = argv[argc - 1];
 911
 912	/* Print the command if xflag is set. */
 913	if (xflag)
 914		xtracecommand(&varlist, argc, argv);
 915
 916	/* Now locate the command. */
 917	if (argc == 0) {
 918		/* Variable assignment(s) without command */
 919		cmdentry.cmdtype = CMDBUILTIN;
 920		cmdentry.u.index = BLTINCMD;
 921		cmdentry.special = 0;
 922	} else {
 923		static const char PATH[] = "PATH=";
 924		int cmd_flags = 0, bltinonly = 0;
 925
 926		/*
 927		 * Modify the command lookup path, if a PATH= assignment
 928		 * is present
 929		 */
 930		for (i = 0; i < varlist.count; i++)
 931			if (strncmp(varlist.args[i], PATH, sizeof(PATH) - 1) == 0) {
 932				path = varlist.args[i] + sizeof(PATH) - 1;
 933				/*
 934				 * On `PATH=... command`, we need to make
 935				 * sure that the command isn't using the
 936				 * non-updated hash table of the outer PATH
 937				 * setting and we need to make sure that
 938				 * the hash table isn't filled with items
 939				 * from the temporary setting.
 940				 *
 941				 * It would be better to forbid using and
 942				 * updating the table while this command
 943				 * runs, by the command finding mechanism
 944				 * is heavily integrated with hash handling,
 945				 * so we just delete the hash before and after
 946				 * the command runs. Partly deleting like
 947				 * changepatch() does doesn't seem worth the
 948				 * booking effort, since most such runs add
 949				 * directories in front of the new PATH.
 950				 */
 951				clearcmdentry();
 952				do_clearcmdentry = 1;
 953			}
 954
 955		for (;;) {
 956			if (bltinonly) {
 957				cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
 958				if (cmdentry.u.index < 0) {
 959					cmdentry.u.index = BLTINCMD;
 960					argv--;
 961					argc++;
 962					break;
 963				}
 964			} else
 965				find_command(argv[0], &cmdentry, cmd_flags, path);
 966			/* implement the bltin and command builtins here */
 967			if (cmdentry.cmdtype != CMDBUILTIN)
 968				break;
 969			if (cmdentry.u.index == BLTINCMD) {
 970				if (argc == 1)
 971					break;
 972				argv++;
 973				argc--;
 974				bltinonly = 1;
 975			} else if (cmdentry.u.index == COMMANDCMD) {
 976				if (argc == 1)
 977					break;
 978				if (!strcmp(argv[1], "-p")) {
 979					if (argc == 2)
 980						break;
 981					if (argv[2][0] == '-') {
 982						if (strcmp(argv[2], "--"))
 983							break;
 984						if (argc == 3)
 985							break;
 986						argv += 3;
 987						argc -= 3;
 988					} else {
 989						argv += 2;
 990						argc -= 2;
 991					}
 992					path = _PATH_STDPATH;
 993					clearcmdentry();
 994					do_clearcmdentry = 1;
 995				} else if (!strcmp(argv[1], "--")) {
 996					if (argc == 2)
 997						break;
 998					argv += 2;
 999					argc -= 2;
1000				} else if (argv[1][0] == '-')
1001					break;
1002				else {
1003					argv++;
1004					argc--;
1005				}
1006				cmd_flags |= DO_NOFUNC;
1007				bltinonly = 0;
1008			} else
1009				break;
1010		}
1011		/*
1012		 * Special builtins lose their special properties when
1013		 * called via 'command'.
1014		 */
1015		if (cmd_flags & DO_NOFUNC)
1016			cmdentry.special = 0;
1017	}
1018
1019	/* Fork off a child process if necessary. */
1020	if (((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
1021	    && ((flags & EV_EXIT) == 0 || have_traps()))
1022	 || ((flags & EV_BACKCMD) != 0
1023	    && (cmdentry.cmdtype != CMDBUILTIN ||
1024		 !safe_builtin(cmdentry.u.index, argc, argv)))) {
1025		jp = makejob(cmd, 1);
1026		mode = FORK_FG;
1027		if (flags & EV_BACKCMD) {
1028			mode = FORK_NOJOB;
1029			if (pipe(pip) < 0)
1030				error("Pipe call failed: %s", strerror(errno));
1031		}
1032		if (cmdentry.cmdtype == CMDNORMAL &&
1033		    (cmd->ncmd.redirect == NULL || (flags & EV_BACKCMD) == 0) &&
1034		    varlist.count == 0 &&
1035		    (mode == FORK_FG || mode == FORK_NOJOB) &&
1036		    !disvforkset() && !iflag && !mflag) {
1037			if (cmd->ncmd.redirect != NULL) {
1038				if (redirected_vforkexecshell(jp,
1039				    cmd->ncmd.redirect,
1040				    argv, environment(), path,
1041				    cmdentry.u.index))
1042					goto parent;
1043				else
1044					goto out;
1045			} else
1046				vforkexecshell(jp, argv, environment(), path,
1047				    cmdentry.u.index,
1048				    flags & EV_BACKCMD ? pip : NULL);
1049			goto parent;
1050		}
1051		if (forkshell(jp, cmd, mode) != 0)
1052			goto parent;	/* at end of routine */
1053		if (flags & EV_BACKCMD) {
1054			FORCEINTON;
1055			close(pip[0]);
1056			if (pip[1] != 1) {
1057				dup2(pip[1], 1);
1058				close(pip[1]);
1059			}
1060			flags &= ~EV_BACKCMD;
1061		}
1062		flags |= EV_EXIT;
1063	}
1064
1065	/* This is the child process if a fork occurred. */
1066	/* Execute the command. */
1067	if (cmdentry.cmdtype == CMDFUNCTION) {
1068#ifdef DEBUG
1069		trputs("Shell function:  ");  trargs(argv);
1070#endif
1071		saveparam = shellparam;
1072		shellparam.malloc = 0;
1073		shellparam.reset = 1;
1074		shellparam.nparam = argc - 1;
1075		shellparam.p = argv + 1;
1076		shellparam.optp = NULL;
1077		shellparam.optnext = NULL;
1078		INTOFF;
1079		savelocalvars = localvars;
1080		localvars = NULL;
1081		reffunc(cmdentry.u.func);
1082		savehandler = handler;
1083		if (setjmp(jmploc.loc)) {
1084			popredir();
1085			unreffunc(cmdentry.u.func);
1086			poplocalvars();
1087			localvars = savelocalvars;
1088			freeparam(&shellparam);
1089			shellparam = saveparam;
1090			funcnest--;
1091			handler = savehandler;
1092			longjmp(handler->loc, 1);
1093		}
1094		handler = &jmploc;
1095		funcnest++;
1096		redirect(cmd->ncmd.redirect, REDIR_PUSH);
1097		INTON;
1098		for (i = 0; i < varlist.count; i++)
1099			mklocal(varlist.args[i]);
1100		exitstatus = oexitstatus;
1101		evaltree(getfuncnode(cmdentry.u.func),
1102		    flags & (EV_TESTED | EV_EXIT));
1103		INTOFF;
1104		unreffunc(cmdentry.u.func);
1105		poplocalvars();
1106		localvars = savelocalvars;
1107		freeparam(&shellparam);
1108		shellparam = saveparam;
1109		handler = savehandler;
1110		funcnest--;
1111		popredir();
1112		INTON;
1113		if (evalskip == SKIPRETURN) {
1114			evalskip = 0;
1115			skipcount = 0;
1116		}
1117		if (jp)
1118			exitshell(exitstatus);
1119	} else if (cmdentry.cmdtype == CMDBUILTIN) {
1120#ifdef DEBUG
1121		trputs("builtin command:  ");  trargs(argv);
1122#endif
1123		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
1124		if (flags == EV_BACKCMD) {
1125			memout.nextc = memout.buf;
1126			mode |= REDIR_BACKQ;
1127		}
1128		savecmdname = commandname;
1129		savetopfile = getcurrentfile();
1130		cmdenviron = &varlist;
1131		e = -1;
1132		savehandler = handler;
1133		if (setjmp(jmploc.loc)) {
1134			e = exception;
1135			if (e == EXINT)
1136				exitstatus = SIGINT+128;
1137			goto cmddone;
1138		}
1139		handler = &jmploc;
1140		redirect(cmd->ncmd.redirect, mode);
1141		outclearerror(out1);
1142		/*
1143		 * If there is no command word, redirection errors should
1144		 * not be fatal but assignment errors should.
1145		 */
1146		if (argc == 0)
1147			cmdentry.special = 1;
1148		listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
1149		if (argc > 0)
1150			bltinsetlocale();
1151		commandname = argv[0];
1152		argptr = argv + 1;
1153		nextopt_optptr = NULL;		/* initialize nextopt */
1154		builtin_flags = flags;
1155		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
1156		flushall();
1157		if (outiserror(out1)) {
1158			warning("write error on stdout");
1159			if (exitstatus == 0 || exitstatus == 1)
1160				exitstatus = 2;
1161		}
1162cmddone:
1163		if (argc > 0)
1164			bltinunsetlocale();
1165		cmdenviron = NULL;
1166		out1 = &output;
1167		out2 = &errout;
1168		freestdout();
1169		handler = savehandler;
1170		commandname = savecmdname;
1171		if (jp)
1172			exitshell(exitstatus);
1173		if (flags == EV_BACKCMD) {
1174			backcmd->buf = memout.buf;
1175			backcmd->nleft = memout.buf != NULL ?
1176			    memout.nextc - memout.buf : 0;
1177			memout.buf = NULL;
1178			memout.nextc = NULL;
1179			memout.bufend = NULL;
1180			memout.bufsize = 64;
1181		}
1182		if (cmdentry.u.index != EXECCMD)
1183			popredir();
1184		if (e != -1) {
1185			if (e != EXERROR || cmdentry.special)
1186				exraise(e);
1187			popfilesupto(savetopfile);
1188			if (flags != EV_BACKCMD)
1189				FORCEINTON;
1190		}
1191	} else {
1192#ifdef DEBUG
1193		trputs("normal command:  ");  trargs(argv);
1194#endif
1195		redirect(cmd->ncmd.redirect, 0);
1196		for (i = 0; i < varlist.count; i++)
1197			setvareq(varlist.args[i], VEXPORT|VSTACK);
1198		envp = environment();
1199		shellexec(argv, envp, path, cmdentry.u.index);
1200		/*NOTREACHED*/
1201	}
1202	goto out;
1203
1204parent:	/* parent process gets here (if we forked) */
1205	if (mode == FORK_FG) {	/* argument to fork */
1206		INTOFF;
1207		exitstatus = waitforjob(jp, &signaled);
1208		INTON;
1209		if (iflag && loopnest > 0 && signaled) {
1210			evalskip = SKIPBREAK;
1211			skipcount = loopnest;
1212		}
1213	} else if (mode == FORK_NOJOB) {
1214		backcmd->fd = pip[0];
1215		close(pip[1]);
1216		backcmd->jp = jp;
1217	}
1218
1219out:
1220	if (lastarg)
1221		setvar("_", lastarg, 0);
1222	if (do_clearcmdentry)
1223		clearcmdentry();
1224}
1225
1226
1227
1228/*
1229 * Search for a command.  This is called before we fork so that the
1230 * location of the command will be available in the parent as well as
1231 * the child.  The check for "goodname" is an overly conservative
1232 * check that the name will not be subject to expansion.
1233 */
1234
1235static void
1236prehash(union node *n)
1237{
1238	struct cmdentry entry;
1239
1240	if (n && n->type == NCMD && n->ncmd.args)
1241		if (goodname(n->ncmd.args->narg.text))
1242			find_command(n->ncmd.args->narg.text, &entry, 0,
1243				     pathval());
1244}
1245
1246
1247
1248/*
1249 * Builtin commands.  Builtin commands whose functions are closely
1250 * tied to evaluation are implemented here.
1251 */
1252
1253/*
1254 * No command given, a bltin command with no arguments, or a bltin command
1255 * with an invalid name.
1256 */
1257
1258int
1259bltincmd(int argc, char **argv)
1260{
1261	if (argc > 1) {
1262		out2fmt_flush("%s: not found\n", argv[1]);
1263		return 127;
1264	}
1265	/*
1266	 * Preserve exitstatus of a previous possible command substitution
1267	 * as POSIX mandates
1268	 */
1269	return exitstatus;
1270}
1271
1272
1273/*
1274 * Handle break and continue commands.  Break, continue, and return are
1275 * all handled by setting the evalskip flag.  The evaluation routines
1276 * above all check this flag, and if it is set they start skipping
1277 * commands rather than executing them.  The variable skipcount is
1278 * the number of loops to break/continue, or the number of function
1279 * levels to return.  (The latter is always 1.)  It should probably
1280 * be an error to break out of more loops than exist, but it isn't
1281 * in the standard shell so we don't make it one here.
1282 */
1283
1284int
1285breakcmd(int argc, char **argv)
1286{
1287	long n;
1288	char *end;
1289
1290	if (argc > 1) {
1291		/* Allow arbitrarily large numbers. */
1292		n = strtol(argv[1], &end, 10);
1293		if (!is_digit(argv[1][0]) || *end != '\0')
1294			error("Illegal number: %s", argv[1]);
1295	} else
1296		n = 1;
1297	if (n > loopnest)
1298		n = loopnest;
1299	if (n > 0) {
1300		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1301		skipcount = n;
1302	}
1303	return 0;
1304}
1305
1306/*
1307 * The `command' command.
1308 */
1309int
1310commandcmd(int argc __unused, char **argv __unused)
1311{
1312	const char *path;
1313	int ch;
1314	int cmd = -1;
1315
1316	path = bltinlookup("PATH", 1);
1317
1318	while ((ch = nextopt("pvV")) != '\0') {
1319		switch (ch) {
1320		case 'p':
1321			path = _PATH_STDPATH;
1322			break;
1323		case 'v':
1324			cmd = TYPECMD_SMALLV;
1325			break;
1326		case 'V':
1327			cmd = TYPECMD_BIGV;
1328			break;
1329		}
1330	}
1331
1332	if (cmd != -1) {
1333		if (*argptr == NULL || argptr[1] != NULL)
1334			error("wrong number of arguments");
1335		return typecmd_impl(2, argptr - 1, cmd, path);
1336	}
1337	if (*argptr != NULL)
1338		error("commandcmd bad call");
1339
1340	/*
1341	 * Do nothing successfully if no command was specified;
1342	 * ksh also does this.
1343	 */
1344	return 0;
1345}
1346
1347
1348/*
1349 * The return command.
1350 */
1351
1352int
1353returncmd(int argc, char **argv)
1354{
1355	int ret = argc > 1 ? number(argv[1]) : oexitstatus;
1356
1357	evalskip = SKIPRETURN;
1358	skipcount = 1;
1359	return ret;
1360}
1361
1362
1363int
1364falsecmd(int argc __unused, char **argv __unused)
1365{
1366	return 1;
1367}
1368
1369
1370int
1371truecmd(int argc __unused, char **argv __unused)
1372{
1373	return 0;
1374}
1375
1376
1377int
1378execcmd(int argc, char **argv)
1379{
1380	int i;
1381
1382	/*
1383	 * Because we have historically not supported any options,
1384	 * only treat "--" specially.
1385	 */
1386	if (argc > 1 && strcmp(argv[1], "--") == 0)
1387		argc--, argv++;
1388	if (argc > 1) {
1389		iflag = 0;		/* exit on error */
1390		mflag = 0;
1391		optschanged();
1392		for (i = 0; i < cmdenviron->count; i++)
1393			setvareq(cmdenviron->args[i], VEXPORT|VSTACK);
1394		shellexec(argv + 1, environment(), pathval(), 0);
1395
1396	}
1397	return 0;
1398}
1399
1400
1401int
1402timescmd(int argc __unused, char **argv __unused)
1403{
1404	struct rusage ru;
1405	long shumins, shsmins, chumins, chsmins;
1406	double shusecs, shssecs, chusecs, chssecs;
1407
1408	if (getrusage(RUSAGE_SELF, &ru) < 0)
1409		return 1;
1410	shumins = ru.ru_utime.tv_sec / 60;
1411	shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1412	shsmins = ru.ru_stime.tv_sec / 60;
1413	shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1414	if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
1415		return 1;
1416	chumins = ru.ru_utime.tv_sec / 60;
1417	chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1418	chsmins = ru.ru_stime.tv_sec / 60;
1419	chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1420	out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
1421	    shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
1422	return 0;
1423}