• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*	$NetBSD: eval.c,v 1.81.2.1 2005/06/13 22:03:51 tron Exp $	*/
2  
3  /*-
4   * Copyright (c) 1993
5   *	The Regents of the University of California.  All rights reserved.
6   *
7   * This code is derived from software contributed to Berkeley by
8   * Kenneth Almquist.
9   *
10   * Redistribution and use in source and binary forms, with or without
11   * modification, are permitted provided that the following conditions
12   * are met:
13   * 1. Redistributions of source code must retain the above copyright
14   *    notice, this list of conditions and the following disclaimer.
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in the
17   *    documentation and/or other materials provided with the distribution.
18   * 3. Neither the name of the University nor the names of its contributors
19   *    may be used to endorse or promote products derived from this software
20   *    without specific prior written permission.
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32   * SUCH DAMAGE.
33   */
34  
35  #include <sys/cdefs.h>
36  #ifndef lint
37  #if 0
38  static char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 6/8/95";
39  #else
40  __RCSID("$NetBSD: eval.c,v 1.81.2.1 2005/06/13 22:03:51 tron Exp $");
41  #endif
42  #endif /* not lint */
43  
44  #include <stdlib.h>
45  #include <signal.h>
46  #include <stdio.h>
47  #include <unistd.h>
48  #ifdef __linux__
49  #include <fcntl.h>
50  #else
51  #include <sys/fcntl.h>
52  #endif
53  #include <sys/times.h>
54  #include <sys/param.h>
55  #include <sys/types.h>
56  #include <sys/wait.h>
57  
58  /*
59   * Evaluate a command.
60   */
61  
62  #include "shell.h"
63  #include "nodes.h"
64  #include "syntax.h"
65  #include "expand.h"
66  #include "parser.h"
67  #include "jobs.h"
68  #include "eval.h"
69  #include "builtins.h"
70  #include "options.h"
71  #include "exec.h"
72  #include "redir.h"
73  #include "input.h"
74  #include "output.h"
75  #include "trap.h"
76  #include "var.h"
77  #include "memalloc.h"
78  #include "error.h"
79  #include "show.h"
80  #include "mystring.h"
81  #include "main.h"
82  #ifndef SMALL
83  #include "myhistedit.h"
84  #endif
85  
86  
87  /* flags in argument to evaltree */
88  #define EV_EXIT 01		/* exit after evaluating tree */
89  #define EV_TESTED 02		/* exit status is checked; ignore -e flag */
90  #define EV_BACKCMD 04		/* command executing within back quotes */
91  
92  int evalskip;			/* set if we are skipping commands */
93  STATIC int skipcount;		/* number of levels to skip */
94  MKINIT int loopnest;		/* current loop nesting level */
95  int funcnest;			/* depth of function calls */
96  
97  
98  char *commandname;
99  struct strlist *cmdenviron;
100  int exitstatus;			/* exit status of last command */
101  int back_exitstatus;		/* exit status of backquoted command */
102  
103  
104  STATIC void evalloop(union node *, int);
105  STATIC void evalfor(union node *, int);
106  STATIC void evalcase(union node *, int);
107  STATIC void evalsubshell(union node *, int);
108  STATIC void expredir(union node *);
109  STATIC void evalpipe(union node *);
110  STATIC void evalcommand(union node *, int, struct backcmd *);
111  STATIC void prehash(union node *);
112  
113  
114  /*
115   * Called to reset things after an exception.
116   */
117  
118  #ifdef mkinit
119  INCLUDE "eval.h"
120  
121  RESET {
122  	evalskip = 0;
123  	loopnest = 0;
124  	funcnest = 0;
125  }
126  
127  SHELLPROC {
128  	exitstatus = 0;
129  }
130  #endif
131  
132  static int
sh_pipe(int fds[2])133  sh_pipe(int fds[2])
134  {
135  	int nfd;
136  
137  	if (pipe(fds))
138  		return -1;
139  
140  	if (fds[0] < 3) {
141  		nfd = fcntl(fds[0], F_DUPFD, 3);
142  		if (nfd != -1) {
143  			close(fds[0]);
144  			fds[0] = nfd;
145  		}
146  	}
147  
148  	if (fds[1] < 3) {
149  		nfd = fcntl(fds[1], F_DUPFD, 3);
150  		if (nfd != -1) {
151  			close(fds[1]);
152  			fds[1] = nfd;
153  		}
154  	}
155  	return 0;
156  }
157  
158  
159  /*
160   * The eval commmand.
161   */
162  
163  int
evalcmd(int argc,char ** argv)164  evalcmd(int argc, char **argv)
165  {
166          char *p;
167          char *concat;
168          char **ap;
169  
170          if (argc > 1) {
171                  p = argv[1];
172                  if (argc > 2) {
173                          STARTSTACKSTR(concat);
174                          ap = argv + 2;
175                          for (;;) {
176                                  while (*p)
177                                          STPUTC(*p++, concat);
178                                  if ((p = *ap++) == NULL)
179                                          break;
180                                  STPUTC(' ', concat);
181                          }
182                          STPUTC('\0', concat);
183                          p = grabstackstr(concat);
184                  }
185                  evalstring(p, EV_TESTED);
186          }
187          return exitstatus;
188  }
189  
190  
191  /*
192   * Execute a command or commands contained in a string.
193   */
194  
195  void
evalstring(char * s,int flag)196  evalstring(char *s, int flag)
197  {
198  	union node *n;
199  	struct stackmark smark;
200  
201  	setstackmark(&smark);
202  	setinputstring(s, 1);
203  
204  	while ((n = parsecmd(0)) != NEOF) {
205  		evaltree(n, flag);
206  		popstackmark(&smark);
207  	}
208  	popfile();
209  	popstackmark(&smark);
210  }
211  
212  
213  
214  /*
215   * Evaluate a parse tree.  The value is left in the global variable
216   * exitstatus.
217   */
218  
219  void
evaltree(union node * n,int flags)220  evaltree(union node *n, int flags)
221  {
222  	if (n == NULL) {
223  		TRACE(("evaltree(NULL) called\n"));
224  		exitstatus = 0;
225  		goto out;
226  	}
227  #ifdef WITH_HISTORY
228  	displayhist = 1;	/* show history substitutions done with fc */
229  #endif
230  	TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
231  	    getpid(), n, n->type, flags));
232  	switch (n->type) {
233  	case NSEMI:
234  		evaltree(n->nbinary.ch1, flags & EV_TESTED);
235  		if (evalskip)
236  			goto out;
237  		evaltree(n->nbinary.ch2, flags);
238  		break;
239  	case NAND:
240  		evaltree(n->nbinary.ch1, EV_TESTED);
241  		if (evalskip || exitstatus != 0)
242  			goto out;
243  		evaltree(n->nbinary.ch2, flags);
244  		break;
245  	case NOR:
246  		evaltree(n->nbinary.ch1, EV_TESTED);
247  		if (evalskip || exitstatus == 0)
248  			goto out;
249  		evaltree(n->nbinary.ch2, flags);
250  		break;
251  	case NREDIR:
252  		expredir(n->nredir.redirect);
253  		redirect(n->nredir.redirect, REDIR_PUSH);
254  		evaltree(n->nredir.n, flags);
255  		popredir();
256  		break;
257  	case NSUBSHELL:
258  		evalsubshell(n, flags);
259  		break;
260  	case NBACKGND:
261  		evalsubshell(n, flags);
262  		break;
263  	case NIF: {
264  		evaltree(n->nif.test, EV_TESTED);
265  		if (evalskip)
266  			goto out;
267  		if (exitstatus == 0)
268  			evaltree(n->nif.ifpart, flags);
269  		else if (n->nif.elsepart)
270  			evaltree(n->nif.elsepart, flags);
271  		else
272  			exitstatus = 0;
273  		break;
274  	}
275  	case NWHILE:
276  	case NUNTIL:
277  		evalloop(n, flags);
278  		break;
279  	case NFOR:
280  		evalfor(n, flags);
281  		break;
282  	case NCASE:
283  		evalcase(n, flags);
284  		break;
285  	case NDEFUN:
286  		defun(n->narg.text, n->narg.next);
287  		exitstatus = 0;
288  		break;
289  	case NNOT:
290  		evaltree(n->nnot.com, EV_TESTED);
291  		exitstatus = !exitstatus;
292  		break;
293  	case NPIPE:
294  		evalpipe(n);
295  		break;
296  	case NCMD:
297  		evalcommand(n, flags, (struct backcmd *)NULL);
298  		break;
299  	default:
300  		out1fmt("Node type = %d\n", n->type);
301  		flushout(&output);
302  		break;
303  	}
304  out:
305  	if (pendingsigs)
306  		dotrap();
307  	if ((flags & EV_EXIT) != 0)
308  		exitshell(exitstatus);
309  }
310  
311  
312  STATIC void
evalloop(union node * n,int flags)313  evalloop(union node *n, int flags)
314  {
315  	int status;
316  
317  	loopnest++;
318  	status = 0;
319  	for (;;) {
320  		evaltree(n->nbinary.ch1, EV_TESTED);
321  		if (evalskip) {
322  skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
323  				evalskip = 0;
324  				continue;
325  			}
326  			if (evalskip == SKIPBREAK && --skipcount <= 0)
327  				evalskip = 0;
328  			break;
329  		}
330  		if (n->type == NWHILE) {
331  			if (exitstatus != 0)
332  				break;
333  		} else {
334  			if (exitstatus == 0)
335  				break;
336  		}
337  		evaltree(n->nbinary.ch2, flags & EV_TESTED);
338  		status = exitstatus;
339  		if (evalskip)
340  			goto skipping;
341  	}
342  	loopnest--;
343  	exitstatus = status;
344  }
345  
346  
347  
348  STATIC void
evalfor(union node * n,int flags)349  evalfor(union node *n, int flags)
350  {
351  	struct arglist arglist;
352  	union node *argp;
353  	struct strlist *sp;
354  	struct stackmark smark;
355  	int status = 0;
356  
357  	setstackmark(&smark);
358  	arglist.lastp = &arglist.list;
359  	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
360  		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
361  		if (evalskip)
362  			goto out;
363  	}
364  	*arglist.lastp = NULL;
365  
366  	loopnest++;
367  	for (sp = arglist.list ; sp ; sp = sp->next) {
368  		setvar(n->nfor.var, sp->text, 0);
369  		evaltree(n->nfor.body, flags & EV_TESTED);
370  		status = exitstatus;
371  		if (evalskip) {
372  			if (evalskip == SKIPCONT && --skipcount <= 0) {
373  				evalskip = 0;
374  				continue;
375  			}
376  			if (evalskip == SKIPBREAK && --skipcount <= 0)
377  				evalskip = 0;
378  			break;
379  		}
380  	}
381  	loopnest--;
382  	exitstatus = status;
383  out:
384  	popstackmark(&smark);
385  }
386  
387  
388  
389  STATIC void
evalcase(union node * n,int flags)390  evalcase(union node *n, int flags)
391  {
392  	union node *cp;
393  	union node *patp;
394  	struct arglist arglist;
395  	struct stackmark smark;
396  	int status = 0;
397  
398  	setstackmark(&smark);
399  	arglist.lastp = &arglist.list;
400  	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
401  	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
402  		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
403  			if (casematch(patp, arglist.list->text)) {
404  				if (evalskip == 0) {
405  					evaltree(cp->nclist.body, flags);
406  					status = exitstatus;
407  				}
408  				goto out;
409  			}
410  		}
411  	}
412  out:
413  	exitstatus = status;
414  	popstackmark(&smark);
415  }
416  
417  
418  
419  /*
420   * Kick off a subshell to evaluate a tree.
421   */
422  
423  STATIC void
evalsubshell(union node * n,int flags)424  evalsubshell(union node *n, int flags)
425  {
426  	struct job *jp;
427  	int backgnd = (n->type == NBACKGND);
428  
429  	expredir(n->nredir.redirect);
430  	INTOFF;
431  	jp = makejob(n, 1);
432  	if (forkshell(jp, n, backgnd) == 0) {
433  		INTON;
434  		if (backgnd)
435  			flags &=~ EV_TESTED;
436  		redirect(n->nredir.redirect, 0);
437  		/* never returns */
438  		evaltree(n->nredir.n, flags | EV_EXIT);
439  	}
440  	if (! backgnd)
441  		exitstatus = waitforjob(jp);
442  	INTON;
443  }
444  
445  
446  
447  /*
448   * Compute the names of the files in a redirection list.
449   */
450  
451  STATIC void
expredir(union node * n)452  expredir(union node *n)
453  {
454  	union node *redir;
455  
456  	for (redir = n ; redir ; redir = redir->nfile.next) {
457  		struct arglist fn;
458  		fn.lastp = &fn.list;
459  		switch (redir->type) {
460  		case NFROMTO:
461  		case NFROM:
462  		case NTO:
463  		case NCLOBBER:
464  		case NAPPEND:
465  			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
466  			redir->nfile.expfname = fn.list->text;
467  			break;
468  		case NFROMFD:
469  		case NTOFD:
470  			if (redir->ndup.vname) {
471  				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
472  				fixredir(redir, fn.list->text, 1);
473  			}
474  			break;
475  		}
476  	}
477  }
478  
479  
480  
481  /*
482   * Evaluate a pipeline.  All the processes in the pipeline are children
483   * of the process creating the pipeline.  (This differs from some versions
484   * of the shell, which make the last process in a pipeline the parent
485   * of all the rest.)
486   */
487  
488  STATIC void
evalpipe(union node * n)489  evalpipe(union node *n)
490  {
491  	struct job *jp;
492  	struct nodelist *lp;
493  	int pipelen;
494  	int prevfd;
495  	int pip[2];
496  
497  	TRACE(("evalpipe(0x%lx) called\n", (long)n));
498  	pipelen = 0;
499  	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
500  		pipelen++;
501  	INTOFF;
502  	jp = makejob(n, pipelen);
503  	prevfd = -1;
504  	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
505  		prehash(lp->n);
506  		pip[1] = -1;
507  		if (lp->next) {
508  			if (sh_pipe(pip) < 0) {
509  				close(prevfd);
510  				error("Pipe call failed");
511  			}
512  		}
513  		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
514  			INTON;
515  			if (prevfd > 0) {
516  				close(0);
517  				copyfd(prevfd, 0);
518  				close(prevfd);
519  			}
520  			if (pip[1] >= 0) {
521  				close(pip[0]);
522  				if (pip[1] != 1) {
523  					close(1);
524  					copyfd(pip[1], 1);
525  					close(pip[1]);
526  				}
527  			}
528  			evaltree(lp->n, EV_EXIT);
529  		}
530  		if (prevfd >= 0)
531  			close(prevfd);
532  		prevfd = pip[0];
533  		close(pip[1]);
534  	}
535  	if (n->npipe.backgnd == 0) {
536  		exitstatus = waitforjob(jp);
537  		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
538  	}
539  	INTON;
540  }
541  
542  
543  
544  /*
545   * Execute a command inside back quotes.  If it's a builtin command, we
546   * want to save its output in a block obtained from malloc.  Otherwise
547   * we fork off a subprocess and get the output of the command via a pipe.
548   * Should be called with interrupts off.
549   */
550  
551  void
evalbackcmd(union node * n,struct backcmd * result)552  evalbackcmd(union node *n, struct backcmd *result)
553  {
554  	int pip[2];
555  	struct job *jp;
556  	struct stackmark smark;		/* unnecessary */
557  
558  	setstackmark(&smark);
559  	result->fd = -1;
560  	result->buf = NULL;
561  	result->nleft = 0;
562  	result->jp = NULL;
563  	if (n == NULL) {
564  		goto out;
565  	}
566  #ifdef notyet
567  	/*
568  	 * For now we disable executing builtins in the same
569  	 * context as the shell, because we are not keeping
570  	 * enough state to recover from changes that are
571  	 * supposed only to affect subshells. eg. echo "`cd /`"
572  	 */
573  	if (n->type == NCMD) {
574  		exitstatus = oexitstatus;
575  		evalcommand(n, EV_BACKCMD, result);
576  	} else
577  #endif
578  	{
579  		INTOFF;
580  		if (sh_pipe(pip) < 0)
581  			error("Pipe call failed");
582  		jp = makejob(n, 1);
583  		if (forkshell(jp, n, FORK_NOJOB) == 0) {
584  			FORCEINTON;
585  			close(pip[0]);
586  			if (pip[1] != 1) {
587  				close(1);
588  				copyfd(pip[1], 1);
589  				close(pip[1]);
590  			}
591  			eflag = 0;
592  			evaltree(n, EV_EXIT);
593  			/* NOTREACHED */
594  		}
595  		close(pip[1]);
596  		result->fd = pip[0];
597  		result->jp = jp;
598  		INTON;
599  	}
600  out:
601  	popstackmark(&smark);
602  	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
603  		result->fd, result->buf, result->nleft, result->jp));
604  }
605  
606  static const char *
syspath(void)607  syspath(void)
608  {
609  	static char *sys_path = NULL;
610  #ifndef __linux__
611  	static int mib[] = {CTL_USER, USER_CS_PATH};
612  #endif
613  	static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
614  
615  	if (sys_path == NULL) {
616  #ifndef __linux__
617  		size_t len;
618  		if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
619  		    (sys_path = ckmalloc(len + 5)) != NULL &&
620  		    sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
621  			memcpy(sys_path, "PATH=", 5);
622  		} else
623  #endif
624  		{
625  			ckfree(sys_path);
626  			/* something to keep things happy */
627  			sys_path = def_path;
628  		}
629  	}
630  	return sys_path;
631  }
632  
633  static int
parse_command_args(int argc,char ** argv,int * use_syspath)634  parse_command_args(int argc, char **argv, int *use_syspath)
635  {
636  	int sv_argc = argc;
637  	char *cp, c;
638  
639  	*use_syspath = 0;
640  
641  	for (;;) {
642  		argv++;
643  		if (--argc == 0)
644  			break;
645  		cp = *argv;
646  		if (*cp++ != '-')
647  			break;
648  		if (*cp == '-' && cp[1] == 0) {
649  			argv++;
650  			argc--;
651  			break;
652  		}
653  		while ((c = *cp++)) {
654  			switch (c) {
655  			case 'p':
656  				*use_syspath = 1;
657  				break;
658  			default:
659  				/* run 'typecmd' for other options */
660  				return 0;
661  			}
662  		}
663  	}
664  	return sv_argc - argc;
665  }
666  
667  int vforked = 0;
668  
669  /*
670   * Execute a simple command.
671   */
672  
673  STATIC void
evalcommand(union node * cmd,int flags,struct backcmd * backcmd)674  evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
675  {
676  	struct stackmark smark;
677  	union node *argp;
678  	struct arglist arglist;
679  	struct arglist varlist;
680  	char **argv;
681  	int argc;
682  	char **envp;
683  	int varflag;
684  	struct strlist *sp;
685  	int mode;
686  	int pip[2];
687  	struct cmdentry cmdentry;
688  	struct job *jp;
689  	struct jmploc jmploc;
690  	struct jmploc *volatile savehandler = 0;
691  	char *volatile savecmdname;
692  	volatile struct shparam saveparam;
693  	struct localvar *volatile savelocalvars;
694  	volatile int e;
695  	char *lastarg;
696  	const char *path = pathval();
697  	volatile int temp_path = 0;
698  #if __GNUC__
699  	/* Avoid longjmp clobbering */
700  	(void) &argv;
701  	(void) &argc;
702  	(void) &lastarg;
703  	(void) &flags;
704  #endif
705  
706  	vforked = 0;
707  	/* First expand the arguments. */
708  	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
709  	setstackmark(&smark);
710  	back_exitstatus = 0;
711  
712  	arglist.lastp = &arglist.list;
713  	varflag = 1;
714  	/* Expand arguments, ignoring the initial 'name=value' ones */
715  	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
716  		char *p = argp->narg.text;
717  		if (varflag && is_name(*p)) {
718  			do {
719  				p++;
720  			} while (is_in_name(*p));
721  			if (*p == '=')
722  				continue;
723  		}
724  		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
725  		varflag = 0;
726  	}
727  	*arglist.lastp = NULL;
728  
729  	expredir(cmd->ncmd.redirect);
730  
731  	/* Now do the initial 'name=value' ones we skipped above */
732  	varlist.lastp = &varlist.list;
733  	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
734  		char *p = argp->narg.text;
735  		if (!is_name(*p))
736  			break;
737  		do
738  			p++;
739  		while (is_in_name(*p));
740  		if (*p != '=')
741  			break;
742  		expandarg(argp, &varlist, EXP_VARTILDE);
743  	}
744  	*varlist.lastp = NULL;
745  
746  	argc = 0;
747  	for (sp = arglist.list ; sp ; sp = sp->next)
748  		argc++;
749  	argv = stalloc(sizeof (char *) * (argc + 1));
750  
751  	for (sp = arglist.list ; sp ; sp = sp->next) {
752  		TRACE(("evalcommand arg: %s\n", sp->text));
753  		*argv++ = sp->text;
754  	}
755  	*argv = NULL;
756  	lastarg = NULL;
757  	if (iflag && funcnest == 0 && argc > 0)
758  		lastarg = argv[-1];
759  	argv -= argc;
760  
761  	/* Print the command if xflag is set. */
762  	if (xflag) {
763  		char sep = 0;
764  		out2str(ps4val());
765  		for (sp = varlist.list ; sp ; sp = sp->next) {
766  			if (sep != 0)
767  				outc(sep, &errout);
768  			out2str(sp->text);
769  			sep = ' ';
770  		}
771  		for (sp = arglist.list ; sp ; sp = sp->next) {
772  			if (sep != 0)
773  				outc(sep, &errout);
774  			out2str(sp->text);
775  			sep = ' ';
776  		}
777  		outc('\n', &errout);
778  		flushout(&errout);
779  	}
780  
781  	/* Now locate the command. */
782  	if (argc == 0) {
783  		cmdentry.cmdtype = CMDSPLBLTIN;
784  		cmdentry.u.bltin = bltincmd;
785  	} else {
786  		static const char PATH[] = "PATH=";
787  		int cmd_flags = DO_ERR;
788  
789  		/*
790  		 * Modify the command lookup path, if a PATH= assignment
791  		 * is present
792  		 */
793  		for (sp = varlist.list; sp; sp = sp->next)
794  			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
795  				path = sp->text + sizeof(PATH) - 1;
796  
797  		do {
798  			int argsused, use_syspath;
799  			find_command(argv[0], &cmdentry, cmd_flags, path);
800  			if (cmdentry.cmdtype == CMDUNKNOWN) {
801  				exitstatus = 127;
802  				flushout(&errout);
803  				goto out;
804  			}
805  
806  			/* implement the 'command' builtin here */
807  			if (cmdentry.cmdtype != CMDBUILTIN ||
808  			    cmdentry.u.bltin != bltincmd)
809  				break;
810  			cmd_flags |= DO_NOFUNC;
811  			argsused = parse_command_args(argc, argv, &use_syspath);
812  			if (argsused == 0) {
813  				/* use 'type' builting to display info */
814  				cmdentry.u.bltin = typecmd;
815  				break;
816  			}
817  			argc -= argsused;
818  			argv += argsused;
819  			if (use_syspath)
820  				path = syspath() + 5;
821  		} while (argc != 0);
822  		if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
823  			/* posix mandates that 'command <splbltin>' act as if
824  			   <splbltin> was a normal builtin */
825  			cmdentry.cmdtype = CMDBUILTIN;
826  	}
827  
828  	/* Fork off a child process if necessary. */
829  	if (cmd->ncmd.backgnd
830  	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
831  	 || ((flags & EV_BACKCMD) != 0
832  	    && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
833  		 || cmdentry.u.bltin == dotcmd
834  		 || cmdentry.u.bltin == evalcmd))) {
835  		INTOFF;
836  		jp = makejob(cmd, 1);
837  		mode = cmd->ncmd.backgnd;
838  		if (flags & EV_BACKCMD) {
839  			mode = FORK_NOJOB;
840  			if (sh_pipe(pip) < 0)
841  				error("Pipe call failed");
842  		}
843  #ifdef DO_SHAREDVFORK
844  		/* It is essential that if DO_SHAREDVFORK is defined that the
845  		 * child's address space is actually shared with the parent as
846  		 * we rely on this.
847  		 */
848  		if (cmdentry.cmdtype == CMDNORMAL) {
849  			pid_t	pid;
850  
851  			savelocalvars = localvars;
852  			localvars = NULL;
853  			vforked = 1;
854  			switch (pid = vfork()) {
855  			case -1:
856  				TRACE(("Vfork failed, errno=%d\n", errno));
857  				INTON;
858  				error("Cannot vfork");
859  				break;
860  			case 0:
861  				/* Make sure that exceptions only unwind to
862  				 * after the vfork(2)
863  				 */
864  				if (setjmp(jmploc.loc)) {
865  					if (exception == EXSHELLPROC) {
866  						/* We can't progress with the vfork,
867  						 * so, set vforked = 2 so the parent
868  						 * knows, and _exit();
869  						 */
870  						vforked = 2;
871  						_exit(0);
872  					} else {
873  						_exit(exerrno);
874  					}
875  				}
876  				savehandler = handler;
877  				handler = &jmploc;
878  				listmklocal(varlist.list, VEXPORT | VNOFUNC);
879  				forkchild(jp, cmd, mode, vforked);
880  				break;
881  			default:
882  				handler = savehandler;	/* restore from vfork(2) */
883  				poplocalvars();
884  				localvars = savelocalvars;
885  				if (vforked == 2) {
886  					vforked = 0;
887  
888  					(void)waitpid(pid, NULL, 0);
889  					/* We need to progress in a normal fork fashion */
890  					goto normal_fork;
891  				}
892  				vforked = 0;
893  				forkparent(jp, cmd, mode, pid);
894  				goto parent;
895  			}
896  		} else {
897  normal_fork:
898  #endif
899  			if (forkshell(jp, cmd, mode) != 0)
900  				goto parent;	/* at end of routine */
901  			FORCEINTON;
902  #ifdef DO_SHAREDVFORK
903  		}
904  #endif
905  		if (flags & EV_BACKCMD) {
906  			if (!vforked) {
907  				FORCEINTON;
908  			}
909  			close(pip[0]);
910  			if (pip[1] != 1) {
911  				close(1);
912  				copyfd(pip[1], 1);
913  				close(pip[1]);
914  			}
915  		}
916  		flags |= EV_EXIT;
917  	}
918  
919  	/* This is the child process if a fork occurred. */
920  	/* Execute the command. */
921  	switch (cmdentry.cmdtype) {
922  	case CMDFUNCTION:
923  #ifdef DEBUG
924  		trputs("Shell function:  ");  trargs(argv);
925  #endif
926  		redirect(cmd->ncmd.redirect, REDIR_PUSH);
927  		saveparam = shellparam;
928  		shellparam.malloc = 0;
929  		shellparam.reset = 1;
930  		shellparam.nparam = argc - 1;
931  		shellparam.p = argv + 1;
932  		shellparam.optnext = NULL;
933  		INTOFF;
934  		savelocalvars = localvars;
935  		localvars = NULL;
936  		INTON;
937  		if (setjmp(jmploc.loc)) {
938  			if (exception == EXSHELLPROC) {
939  				freeparam((volatile struct shparam *)
940  				    &saveparam);
941  			} else {
942  				freeparam(&shellparam);
943  				shellparam = saveparam;
944  			}
945  			poplocalvars();
946  			localvars = savelocalvars;
947  			handler = savehandler;
948  			longjmp(handler->loc, 1);
949  		}
950  		savehandler = handler;
951  		handler = &jmploc;
952  		listmklocal(varlist.list, 0);
953  		/* stop shell blowing its stack */
954  		if (++funcnest > 1000)
955  			error("too many nested function calls");
956  		evaltree(cmdentry.u.func, flags & EV_TESTED);
957  		funcnest--;
958  		INTOFF;
959  		poplocalvars();
960  		localvars = savelocalvars;
961  		freeparam(&shellparam);
962  		shellparam = saveparam;
963  		handler = savehandler;
964  		popredir();
965  		INTON;
966  		if (evalskip == SKIPFUNC) {
967  			evalskip = 0;
968  			skipcount = 0;
969  		}
970  		if (flags & EV_EXIT)
971  			exitshell(exitstatus);
972  		break;
973  
974  	case CMDBUILTIN:
975  	case CMDSPLBLTIN:
976  #ifdef DEBUG
977  		trputs("builtin command:  ");  trargs(argv);
978  #endif
979  		mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
980  		if (flags == EV_BACKCMD) {
981  			memout.nleft = 0;
982  			memout.nextc = memout.buf;
983  			memout.bufsize = 64;
984  			mode |= REDIR_BACKQ;
985  		}
986  		e = -1;
987  		savehandler = handler;
988  		savecmdname = commandname;
989  		handler = &jmploc;
990  		if (!setjmp(jmploc.loc)) {
991  			/* We need to ensure the command hash table isn't
992  			 * corruped by temporary PATH assignments.
993  			 * However we must ensure the 'local' command works!
994  			 */
995  			if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
996  			    cmdentry.u.bltin == typecmd)) {
997  				savelocalvars = localvars;
998  				localvars = 0;
999  				mklocal(path - 5 /* PATH= */, 0);
1000  				temp_path = 1;
1001  			} else
1002  				temp_path = 0;
1003  			redirect(cmd->ncmd.redirect, mode);
1004  
1005  			/* exec is a special builtin, but needs this list... */
1006  			cmdenviron = varlist.list;
1007  			/* we must check 'readonly' flag for all builtins */
1008  			listsetvar(varlist.list,
1009  				cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
1010  			commandname = argv[0];
1011  			/* initialize nextopt */
1012  			argptr = argv + 1;
1013  			optptr = NULL;
1014  			/* and getopt */
1015  #ifndef __linux__
1016  			optreset = 1;
1017  #endif
1018  			optind = 1;
1019  			exitstatus = cmdentry.u.bltin(argc, argv);
1020  		} else {
1021  			e = exception;
1022  			exitstatus = e == EXINT ? SIGINT + 128 :
1023  					e == EXEXEC ? exerrno : 2;
1024  		}
1025  		handler = savehandler;
1026  		flushall();
1027  		out1 = &output;
1028  		out2 = &errout;
1029  		freestdout();
1030  		if (temp_path) {
1031  			poplocalvars();
1032  			localvars = savelocalvars;
1033  		}
1034  		cmdenviron = NULL;
1035  		if (e != EXSHELLPROC) {
1036  			commandname = savecmdname;
1037  			if (flags & EV_EXIT)
1038  				exitshell(exitstatus);
1039  		}
1040  		if (e != -1) {
1041  			if ((e != EXERROR && e != EXEXEC)
1042  			    || cmdentry.cmdtype == CMDSPLBLTIN)
1043  				exraise(e);
1044  			FORCEINTON;
1045  		}
1046  		if (cmdentry.u.bltin != execcmd)
1047  			popredir();
1048  		if (flags == EV_BACKCMD) {
1049  			backcmd->buf = memout.buf;
1050  			backcmd->nleft = memout.nextc - memout.buf;
1051  			memout.buf = NULL;
1052  		}
1053  		break;
1054  
1055  	default:
1056  #ifdef DEBUG
1057  		trputs("normal command:  ");  trargs(argv);
1058  #endif
1059  		clearredir(vforked);
1060  		redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0);
1061  		if (!vforked)
1062  			for (sp = varlist.list ; sp ; sp = sp->next)
1063  				setvareq(sp->text, VEXPORT|VSTACK);
1064  		envp = environment();
1065  		shellexec(argv, envp, path, cmdentry.u.index, vforked);
1066  		break;
1067  	}
1068  	goto out;
1069  
1070  parent:	/* parent process gets here (if we forked) */
1071  	if (mode == FORK_FG) {	/* argument to fork */
1072  		exitstatus = waitforjob(jp);
1073  	} else if (mode == FORK_NOJOB) {
1074  		backcmd->fd = pip[0];
1075  		close(pip[1]);
1076  		backcmd->jp = jp;
1077  	}
1078  	FORCEINTON;
1079  
1080  out:
1081  	if (lastarg)
1082  		/* dsl: I think this is intended to be used to support
1083  		 * '_' in 'vi' command mode during line editing...
1084  		 * However I implemented that within libedit itself.
1085  		 */
1086  		setvar("_", lastarg, 0);
1087  	popstackmark(&smark);
1088  
1089  	if (eflag && exitstatus && !(flags & EV_TESTED))
1090  		exitshell(exitstatus);
1091  }
1092  
1093  
1094  /*
1095   * Search for a command.  This is called before we fork so that the
1096   * location of the command will be available in the parent as well as
1097   * the child.  The check for "goodname" is an overly conservative
1098   * check that the name will not be subject to expansion.
1099   */
1100  
1101  STATIC void
prehash(union node * n)1102  prehash(union node *n)
1103  {
1104  	struct cmdentry entry;
1105  
1106  	if (n->type == NCMD && n->ncmd.args)
1107  		if (goodname(n->ncmd.args->narg.text))
1108  			find_command(n->ncmd.args->narg.text, &entry, 0,
1109  				     pathval());
1110  }
1111  
1112  
1113  
1114  /*
1115   * Builtin commands.  Builtin commands whose functions are closely
1116   * tied to evaluation are implemented here.
1117   */
1118  
1119  /*
1120   * No command given.
1121   */
1122  
1123  int
bltincmd(int argc,char ** argv)1124  bltincmd(int argc, char **argv)
1125  {
1126  	/*
1127  	 * Preserve exitstatus of a previous possible redirection
1128  	 * as POSIX mandates
1129  	 */
1130  	return back_exitstatus;
1131  }
1132  
1133  
1134  /*
1135   * Handle break and continue commands.  Break, continue, and return are
1136   * all handled by setting the evalskip flag.  The evaluation routines
1137   * above all check this flag, and if it is set they start skipping
1138   * commands rather than executing them.  The variable skipcount is
1139   * the number of loops to break/continue, or the number of function
1140   * levels to return.  (The latter is always 1.)  It should probably
1141   * be an error to break out of more loops than exist, but it isn't
1142   * in the standard shell so we don't make it one here.
1143   */
1144  
1145  int
breakcmd(int argc,char ** argv)1146  breakcmd(int argc, char **argv)
1147  {
1148  	int n = argc > 1 ? number(argv[1]) : 1;
1149  
1150  	if (n > loopnest)
1151  		n = loopnest;
1152  	if (n > 0) {
1153  		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1154  		skipcount = n;
1155  	}
1156  	return 0;
1157  }
1158  
1159  
1160  /*
1161   * The return command.
1162   */
1163  
1164  int
returncmd(int argc,char ** argv)1165  returncmd(int argc, char **argv)
1166  {
1167  	int ret = argc > 1 ? number(argv[1]) : exitstatus;
1168  
1169  	if (funcnest) {
1170  		evalskip = SKIPFUNC;
1171  		skipcount = 1;
1172  		return ret;
1173  	}
1174  	else {
1175  		/* Do what ksh does; skip the rest of the file */
1176  		evalskip = SKIPFILE;
1177  		skipcount = 1;
1178  		return ret;
1179  	}
1180  }
1181  
1182  
1183  int
falsecmd(int argc,char ** argv)1184  falsecmd(int argc, char **argv)
1185  {
1186  	return 1;
1187  }
1188  
1189  
1190  int
truecmd(int argc,char ** argv)1191  truecmd(int argc, char **argv)
1192  {
1193  	return 0;
1194  }
1195  
1196  
1197  int
execcmd(int argc,char ** argv)1198  execcmd(int argc, char **argv)
1199  {
1200  	if (argc > 1) {
1201  		struct strlist *sp;
1202  
1203  		iflag = 0;		/* exit on error */
1204  		mflag = 0;
1205  		optschanged();
1206  		for (sp = cmdenviron; sp; sp = sp->next)
1207  			setvareq(sp->text, VEXPORT|VSTACK);
1208  		shellexec(argv + 1, environment(), pathval(), 0, 0);
1209  	}
1210  	return 0;
1211  }
1212  
1213  static int
conv_time(clock_t ticks,char * seconds,size_t l)1214  conv_time(clock_t ticks, char *seconds, size_t l)
1215  {
1216  	static clock_t tpm = 0;
1217  	clock_t mins;
1218  	int i;
1219  
1220  	mins = ticks / tpm;
1221  	snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm );
1222  
1223  	if (seconds[0] == '6' && seconds[1] == '0') {
1224  		/* 59.99995 got rounded up... */
1225  		mins++;
1226  		strlcpy(seconds, "0.0", l);
1227  		return mins;
1228  	}
1229  
1230  	/* suppress trailing zeros */
1231  	i = strlen(seconds) - 1;
1232  	for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--)
1233  		seconds[i] = 0;
1234  	return mins;
1235  }
1236  
1237  int
timescmd(int argc,char ** argv)1238  timescmd(int argc, char **argv)
1239  {
1240  	struct tms tms;
1241  	int u, s, cu, cs;
1242  	char us[8], ss[8], cus[8], css[8];
1243  
1244  	nextopt("");
1245  
1246  	times(&tms);
1247  
1248  	u = conv_time(tms.tms_utime, us, sizeof(us));
1249  	s = conv_time(tms.tms_stime, ss, sizeof(ss));
1250  	cu = conv_time(tms.tms_cutime, cus, sizeof(cus));
1251  	cs = conv_time(tms.tms_cstime, css, sizeof(css));
1252  
1253  	outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n",
1254  		u, us, s, ss, cu, cus, cs, css);
1255  
1256  	return 0;
1257  }
1258