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