loksh-noxz

[fork] a Linux port of OpenBSD's ksh
git clone https://noxz.tech/git/loksh-noxz.git
Log | Files | README

exec.c
1/*	$OpenBSD: exec.c,v 1.76 2022/10/10 14:57:48 kn Exp $	*/
2
3/*
4 * execute command tree
5 */
6
7#include <sys/stat.h>
8
9#include <ctype.h>
10#include <errno.h>
11#include <fcntl.h>
12#include <paths.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17
18#include "sh.h"
19#include "c_test.h"
20
21/* Does ps4 get parameter substitutions done? */
22# define PS4_SUBSTITUTE(s)	substitute((s), 0)
23
24static int	comexec(struct op *, struct tbl *volatile, char **,
25		    int volatile, volatile int *);
26static void	scriptexec(struct op *, char **);
27static int	call_builtin(struct tbl *, char **);
28static int	iosetup(struct ioword *, struct tbl *);
29static int	herein(const char *, int);
30static char	*do_selectargs(char **, bool);
31static int	dbteste_isa(Test_env *, Test_meta);
32static const char *dbteste_getopnd(Test_env *, Test_op, int);
33static int	dbteste_eval(Test_env *, Test_op, const char *, const char *,
34		    int);
35static void	dbteste_error(Test_env *, int, const char *);
36
37
38/*
39 * execute command tree
40 */
41int
42execute(struct op *volatile t,
43    volatile int flags,		/* if XEXEC don't fork */
44    volatile int *xerrok)	/* inform recursive callers in -e mode that
45				 * short-circuit && or || shouldn't be treated
46				 * as an error */
47{
48	int i, dummy = 0, save_xerrok = 0;
49	volatile int rv = 0;
50	int pv[2];
51	char ** volatile ap;
52	char *s, *cp;
53	struct ioword **iowp;
54	struct tbl *tp = NULL;
55
56	if (t == NULL)
57		return 0;
58
59	/* Caller doesn't care if XERROK should propagate. */
60	if (xerrok == NULL)
61		xerrok = &dummy;
62
63	/* Is this the end of a pipeline?  If so, we want to evaluate the
64	 * command arguments
65	bool eval_done = false;
66	if ((flags&XFORK) && !(flags&XEXEC) && (flags&XPCLOSE)) {
67		eval_done = true;
68		tp = eval_execute_args(t, &ap);
69	}
70	 */
71	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
72		return exchild(t, flags & ~XTIME, xerrok, -1); /* run in sub-process */
73
74	newenv(E_EXEC);
75	if (trap)
76		runtraps(0);
77
78	if (t->type == TCOM) {
79		/* Clear subst_exstat before argument expansion.  Used by
80		 * null commands (see comexec() and c_eval()) and by c_set().
81		 */
82		subst_exstat = 0;
83
84		current_lineno = t->lineno;	/* for $LINENO */
85
86		/* POSIX says expand command words first, then redirections,
87		 * and assignments last..
88		 */
89		ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
90		if (flags & XTIME)
91			/* Allow option parsing (bizarre, but POSIX) */
92			timex_hook(t, &ap);
93		if (Flag(FXTRACE) && ap[0]) {
94			shf_fprintf(shl_out, "%s",
95				PS4_SUBSTITUTE(str_val(global("PS4"))));
96			for (i = 0; ap[i]; i++)
97				shf_fprintf(shl_out, "%s%s", ap[i],
98				    ap[i + 1] ? " " : "\n");
99			shf_flush(shl_out);
100		}
101		if (ap[0])
102			tp = findcom(ap[0], FC_BI|FC_FUNC);
103	}
104	flags &= ~XTIME;
105
106	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
107		genv->savefd = areallocarray(NULL, NUFILE, sizeof(short), ATEMP);
108		/* initialize to not redirected */
109		memset(genv->savefd, 0, NUFILE * sizeof(short));
110	}
111
112	/* do redirection, to be restored in quitenv() */
113	if (t->ioact != NULL)
114		for (iowp = t->ioact; *iowp != NULL; iowp++) {
115			if (iosetup(*iowp, tp) < 0) {
116				exstat = rv = 1;
117				/* Except in the permanent case (exec 2>afile),
118				 * redirection failures for special commands
119				 * cause (non-interactive) shell to exit.
120				 */
121				if (tp && tp->val.f != c_exec &&
122				    tp->type == CSHELL &&
123				    (tp->flag & SPEC_BI))
124					errorf(NULL);
125				/* Deal with FERREXIT, quitenv(), etc. */
126				goto Break;
127			}
128		}
129
130	switch (t->type) {
131	case TCOM:
132		rv = comexec(t, tp, ap, flags, xerrok);
133		break;
134
135	case TPAREN:
136		rv = execute(t->left, flags|XFORK, xerrok);
137		break;
138
139	case TPIPE:
140		flags |= XFORK;
141		flags &= ~XEXEC;
142		genv->savefd[0] = savefd(0);
143		genv->savefd[1] = savefd(1);
144		while (t->type == TPIPE) {
145			openpipe(pv);
146			(void) ksh_dup2(pv[1], 1, false); /* stdout of curr */
147			/* Let exchild() close pv[0] in child
148			 * (if this isn't done, commands like
149			 *    (: ; cat /etc/termcap) | sleep 1
150			 *  will hang forever).
151			 */
152			exchild(t->left, flags|XPIPEO|XCCLOSE, NULL, pv[0]);
153			(void) ksh_dup2(pv[0], 0, false); /* stdin of next */
154			closepipe(pv);
155			flags |= XPIPEI;
156			t = t->right;
157		}
158		restfd(1, genv->savefd[1]); /* stdout of last */
159		genv->savefd[1] = 0; /* no need to re-restore this */
160		/* Let exchild() close 0 in parent, after fork, before wait */
161		i = exchild(t, flags|XPCLOSE, xerrok, 0);
162		if (!(flags&XBGND) && !(flags&XXCOM))
163			rv = i;
164		break;
165
166	case TLIST:
167		while (t->type == TLIST) {
168			execute(t->left, flags & XERROK, NULL);
169			t = t->right;
170		}
171		rv = execute(t, flags & XERROK, xerrok);
172		break;
173
174	case TCOPROC:
175	    {
176		sigset_t	omask;
177
178		/* Block sigchild as we are using things changed in the
179		 * signal handler
180		 */
181		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
182		genv->type = E_ERRH;
183		i = sigsetjmp(genv->jbuf, 0);
184		if (i) {
185			sigprocmask(SIG_SETMASK, &omask, NULL);
186			quitenv(NULL);
187			unwind(i);
188			/* NOTREACHED */
189		}
190		/* Already have a (live) co-process? */
191		if (coproc.job && coproc.write >= 0)
192			errorf("coprocess already exists");
193
194		/* Can we re-use the existing co-process pipe? */
195		coproc_cleanup(true);
196
197		/* do this before opening pipes, in case these fail */
198		genv->savefd[0] = savefd(0);
199		genv->savefd[1] = savefd(1);
200
201		openpipe(pv);
202		if (pv[0] != 0) {
203			ksh_dup2(pv[0], 0, false);
204			close(pv[0]);
205		}
206		coproc.write = pv[1];
207		coproc.job = NULL;
208
209		if (coproc.readw >= 0)
210			ksh_dup2(coproc.readw, 1, false);
211		else {
212			openpipe(pv);
213			coproc.read = pv[0];
214			ksh_dup2(pv[1], 1, false);
215			coproc.readw = pv[1];	 /* closed before first read */
216			coproc.njobs = 0;
217			/* create new coprocess id */
218			++coproc.id;
219		}
220		sigprocmask(SIG_SETMASK, &omask, NULL);
221		genv->type = E_EXEC; /* no more need for error handler */
222
223		/* exchild() closes coproc.* in child after fork,
224		 * will also increment coproc.njobs when the
225		 * job is actually created.
226		 */
227		flags &= ~XEXEC;
228		exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
229		    NULL, coproc.readw);
230		break;
231	    }
232
233	case TASYNC:
234		/* XXX non-optimal, I think - "(foo &)", forks for (),
235		 * forks again for async...  parent should optimize
236		 * this to "foo &"...
237		 */
238		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
239		break;
240
241	case TOR:
242	case TAND:
243		rv = execute(t->left, XERROK, xerrok);
244		if ((rv == 0) == (t->type == TAND))
245			rv = execute(t->right, flags & XERROK, xerrok);
246		else {
247			flags |= XERROK;
248			*xerrok = 1;
249		}
250		break;
251
252	case TBANG:
253		rv = !execute(t->right, XERROK, xerrok);
254		flags |= XERROK;
255		*xerrok = 1;
256		break;
257
258	case TDBRACKET:
259	    {
260		Test_env te;
261
262		te.flags = TEF_DBRACKET;
263		te.pos.wp = t->args;
264		te.isa = dbteste_isa;
265		te.getopnd = dbteste_getopnd;
266		te.eval = dbteste_eval;
267		te.error = dbteste_error;
268
269		rv = test_parse(&te);
270		break;
271	    }
272
273	case TFOR:
274	case TSELECT:
275	    {
276		volatile bool is_first = true;
277		ap = (t->vars != NULL) ? eval(t->vars, DOBLANK|DOGLOB|DOTILDE) :
278		    genv->loc->argv + 1;
279		genv->type = E_LOOP;
280		while (1) {
281			i = sigsetjmp(genv->jbuf, 0);
282			if (!i)
283				break;
284			if ((genv->flags&EF_BRKCONT_PASS) ||
285			    (i != LBREAK && i != LCONTIN)) {
286				quitenv(NULL);
287				unwind(i);
288			} else if (i == LBREAK) {
289				rv = 0;
290				goto Break;
291			}
292		}
293		rv = 0; /* in case of a continue */
294		if (t->type == TFOR) {
295			save_xerrok = *xerrok;
296			while (*ap != NULL) {
297				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
298				/* undo xerrok in all iterations except the
299				 * last */
300				*xerrok = save_xerrok;
301				rv = execute(t->left, flags & XERROK, xerrok);
302			}
303			/* ripple xerrok set at final iteration */
304		} else { /* TSELECT */
305			for (;;) {
306				if (!(cp = do_selectargs(ap, is_first))) {
307					rv = 1;
308					break;
309				}
310				is_first = false;
311				setstr(global(t->str), cp, KSH_UNWIND_ERROR);
312				rv = execute(t->left, flags & XERROK, xerrok);
313			}
314		}
315	    }
316		break;
317
318	case TWHILE:
319	case TUNTIL:
320		genv->type = E_LOOP;
321		while (1) {
322			i = sigsetjmp(genv->jbuf, 0);
323			if (!i)
324				break;
325			if ((genv->flags&EF_BRKCONT_PASS) ||
326			    (i != LBREAK && i != LCONTIN)) {
327				quitenv(NULL);
328				unwind(i);
329			} else if (i == LBREAK) {
330				rv = 0;
331				goto Break;
332			}
333		}
334		rv = 0; /* in case of a continue */
335		while ((execute(t->left, XERROK, NULL) == 0) == (t->type == TWHILE))
336			rv = execute(t->right, flags & XERROK, xerrok);
337		break;
338
339	case TIF:
340	case TELIF:
341		if (t->right == NULL)
342			break;	/* should be error */
343		rv = execute(t->left, XERROK, NULL) == 0 ?
344		    execute(t->right->left, flags & XERROK, xerrok) :
345		    execute(t->right->right, flags & XERROK, xerrok);
346		break;
347
348	case TCASE:
349		cp = evalstr(t->str, DOTILDE);
350		for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
351			for (ap = t->vars; *ap; ap++) {
352				if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
353				    gmatch(cp, s, false))
354					goto Found;
355			}
356		}
357		break;
358	  Found:
359		rv = execute(t->left, flags & XERROK, xerrok);
360		break;
361
362	case TBRACE:
363		rv = execute(t->left, flags & XERROK, xerrok);
364		break;
365
366	case TFUNCT:
367		rv = define(t->str, t);
368		break;
369
370	case TTIME:
371		/* Clear XEXEC so nested execute() call doesn't exit
372		 * (allows "ls -l | time grep foo").
373		 */
374		rv = timex(t, flags & ~XEXEC, xerrok);
375		break;
376
377	case TEXEC:		/* an eval'd TCOM */
378		s = t->args[0];
379		ap = makenv();
380		restoresigs();
381		cleanup_proc_env();
382		execve(t->str, t->args, ap);
383		if (errno == ENOEXEC)
384			scriptexec(t, ap);
385		else
386			errorf("%s: %s", s, strerror(errno));
387	}
388    Break:
389	exstat = rv;
390
391	quitenv(NULL);		/* restores IO */
392	if ((flags&XEXEC))
393		unwind(LEXIT);	/* exit child */
394	if (rv != 0 && !(flags & XERROK) && !*xerrok) {
395		trapsig(SIGERR_);
396		if (Flag(FERREXIT))
397			unwind(LERROR);
398	}
399	return rv;
400}
401
402/*
403 * execute simple command
404 */
405
406static int
407comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
408    volatile int *xerrok)
409{
410	int i;
411	volatile int rv = 0;
412	char *cp;
413	char **lastp;
414	struct op texec;
415	int type_flags;
416	int keepasn_ok;
417	int fcflags = FC_BI|FC_FUNC|FC_PATH;
418	int bourne_function_call = 0;
419
420	/* snag the last argument for $_ XXX not the same as at&t ksh,
421	 * which only seems to set $_ after a newline (but not in
422	 * functions/dot scripts, but in interactive and script) -
423	 * perhaps save last arg here and set it in shell()?.
424	 */
425	if (!Flag(FSH) && Flag(FTALKING) && *(lastp = ap)) {
426		while (*++lastp)
427			;
428		/* setstr() can't fail here */
429		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
430		    KSH_RETURN_ERROR);
431	}
432
433	/* Deal with the shell builtins builtin, exec and command since
434	 * they can be followed by other commands.  This must be done before
435	 * we know if we should create a local block, which must be done
436	 * before we can do a path search (in case the assignments change
437	 * PATH).
438	 * Odd cases:
439	 *   FOO=bar exec > /dev/null		FOO is kept but not exported
440	 *   FOO=bar exec foobar		FOO is exported
441	 *   FOO=bar command exec > /dev/null	FOO is neither kept nor exported
442	 *   FOO=bar command			FOO is neither kept nor exported
443	 *   PATH=... foobar			use new PATH in foobar search
444	 */
445	keepasn_ok = 1;
446	while (tp && tp->type == CSHELL) {
447		fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
448		if (tp->val.f == c_builtin) {
449			if ((cp = *++ap) == NULL) {
450				tp = NULL;
451				break;
452			}
453			tp = findcom(cp, FC_BI);
454			if (tp == NULL)
455				errorf("builtin: %s: not a builtin", cp);
456			continue;
457		} else if (tp->val.f == c_exec) {
458			if (ap[1] == NULL)
459				break;
460			ap++;
461			flags |= XEXEC;
462		} else if (tp->val.f == c_command) {
463			int optc, saw_p = 0;
464
465			/* Ugly dealing with options in two places (here and
466			 * in c_command(), but such is life)
467			 */
468			ksh_getopt_reset(&builtin_opt, 0);
469			while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
470				saw_p = 1;
471			if (optc != EOF)
472				break;	/* command -vV or something */
473			/* don't look for functions */
474			fcflags = FC_BI|FC_PATH;
475			if (saw_p) {
476				if (Flag(FRESTRICTED)) {
477					warningf(true,
478					    "command -p: restricted");
479					rv = 1;
480					goto Leave;
481				}
482				fcflags |= FC_DEFPATH;
483			}
484			ap += builtin_opt.optind;
485			/* POSIX says special builtins lose their status
486			 * if accessed using command.
487			 */
488			keepasn_ok = 0;
489			if (!ap[0]) {
490				/* ensure command with no args exits with 0 */
491				subst_exstat = 0;
492				break;
493			}
494		} else
495			break;
496		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
497	}
498	if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
499		type_flags = 0;
500	else {
501		/* create new variable/function block */
502		newblock();
503		/* ksh functions don't keep assignments, POSIX functions do. */
504		if (keepasn_ok && tp && tp->type == CFUNC &&
505		    !(tp->flag & FKSH)) {
506			bourne_function_call = 1;
507			type_flags = 0;
508		} else
509			type_flags = LOCAL|LOCAL_COPY|EXPORT;
510	}
511	if (Flag(FEXPORT))
512		type_flags |= EXPORT;
513	for (i = 0; t->vars[i]; i++) {
514		cp = evalstr(t->vars[i], DOASNTILDE);
515		if (Flag(FXTRACE)) {
516			if (i == 0)
517				shf_fprintf(shl_out, "%s",
518				    PS4_SUBSTITUTE(str_val(global("PS4"))));
519			shf_fprintf(shl_out, "%s%s", cp,
520			    t->vars[i + 1] ? " " : "\n");
521			if (!t->vars[i + 1])
522				shf_flush(shl_out);
523		}
524		typeset(cp, type_flags, 0, 0, 0);
525		if (bourne_function_call && !(type_flags & EXPORT))
526			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
527	}
528
529	if ((cp = *ap) == NULL) {
530		rv = subst_exstat;
531		goto Leave;
532	} else if (!tp) {
533		if (Flag(FRESTRICTED) && strchr(cp, '/')) {
534			warningf(true, "%s: restricted", cp);
535			rv = 1;
536			goto Leave;
537		}
538		tp = findcom(cp, fcflags);
539	}
540
541	switch (tp->type) {
542	case CSHELL:			/* shell built-in */
543		rv = call_builtin(tp, ap);
544		break;
545
546	case CFUNC:			/* function call */
547	    {
548		volatile int old_xflag, old_inuse;
549		const char *volatile old_kshname;
550
551		if (!(tp->flag & ISSET)) {
552			struct tbl *ftp;
553
554			if (!tp->u.fpath) {
555				if (tp->u2.errno_) {
556					warningf(true,
557					    "%s: can't find function "
558					    "definition file - %s",
559					    cp, strerror(tp->u2.errno_));
560					rv = 126;
561				} else {
562					warningf(true,
563					    "%s: can't find function "
564					    "definition file", cp);
565					rv = 127;
566				}
567				break;
568			}
569			if (include(tp->u.fpath, 0, NULL, 0) < 0) {
570				warningf(true,
571				    "%s: can't open function definition file %s - %s",
572				    cp, tp->u.fpath, strerror(errno));
573				rv = 127;
574				break;
575			}
576			if (!(ftp = findfunc(cp, hash(cp), false)) ||
577			    !(ftp->flag & ISSET)) {
578				warningf(true,
579				    "%s: function not defined by %s",
580				    cp, tp->u.fpath);
581				rv = 127;
582				break;
583			}
584			tp = ftp;
585		}
586
587		/* ksh functions set $0 to function name, POSIX functions leave
588		 * $0 unchanged.
589		 */
590		old_kshname = kshname;
591		if (tp->flag & FKSH)
592			kshname = ap[0];
593		else
594			ap[0] = (char *) kshname;
595		genv->loc->argv = ap;
596		for (i = 0; *ap++ != NULL; i++)
597			;
598		genv->loc->argc = i - 1;
599		/* ksh-style functions handle getopts sanely,
600		 * bourne/posix functions are insane...
601		 */
602		if (tp->flag & FKSH) {
603			genv->loc->flags |= BF_DOGETOPTS;
604			genv->loc->getopts_state = user_opt;
605			getopts_reset(1);
606		}
607
608		old_xflag = Flag(FXTRACE);
609		Flag(FXTRACE) = tp->flag & TRACE ? true : false;
610
611		old_inuse = tp->flag & FINUSE;
612		tp->flag |= FINUSE;
613
614		genv->type = E_FUNC;
615		i = sigsetjmp(genv->jbuf, 0);
616		if (i == 0) {
617			/* seems odd to pass XERROK here, but at&t ksh does */
618			exstat = execute(tp->val.t, flags & XERROK, xerrok);
619			i = LRETURN;
620		}
621		kshname = old_kshname;
622		Flag(FXTRACE) = old_xflag;
623		tp->flag = (tp->flag & ~FINUSE) | old_inuse;
624		/* Were we deleted while executing?  If so, free the execution
625		 * tree.  todo: Unfortunately, the table entry is never re-used
626		 * until the lookup table is expanded.
627		 */
628		if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
629			if (tp->flag & ALLOC) {
630				tp->flag &= ~ALLOC;
631				tfree(tp->val.t, tp->areap);
632			}
633			tp->flag = 0;
634		}
635		switch (i) {
636		case LRETURN:
637		case LERROR:
638			rv = exstat;
639			break;
640		case LINTR:
641		case LEXIT:
642		case LLEAVE:
643		case LSHELL:
644			quitenv(NULL);
645			unwind(i);
646			/* NOTREACHED */
647		default:
648			quitenv(NULL);
649			internal_errorf("CFUNC %d", i);
650		}
651		break;
652	    }
653
654	case CEXEC:		/* executable command */
655	case CTALIAS:		/* tracked alias */
656		if (!(tp->flag&ISSET)) {
657			/* errno_ will be set if the named command was found
658			 * but could not be executed (permissions, no execute
659			 * bit, directory, etc).  Print out a (hopefully)
660			 * useful error message and set the exit status to 126.
661			 */
662			if (tp->u2.errno_) {
663				warningf(true, "%s: cannot execute - %s", cp,
664				    strerror(tp->u2.errno_));
665				rv = 126;	/* POSIX */
666			} else {
667				warningf(true, "%s: not found", cp);
668				rv = 127;
669			}
670			break;
671		}
672
673		if (!Flag(FSH)) {
674			/* set $_ to program's full path */
675			/* setstr() can't fail here */
676			setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0),
677			    tp->val.s, KSH_RETURN_ERROR);
678		}
679
680		if (flags&XEXEC) {
681			j_exit();
682			if (!(flags&XBGND) || Flag(FMONITOR)) {
683				setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
684				setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
685			}
686		}
687
688		/* to fork we set up a TEXEC node and call execute */
689		memset(&texec, 0, sizeof(texec));
690		texec.type = TEXEC;
691		texec.left = t;	/* for tprint */
692		texec.str = tp->val.s;
693		texec.args = ap;
694		rv = exchild(&texec, flags, xerrok, -1);
695		break;
696	}
697  Leave:
698	if (flags & XEXEC) {
699		exstat = rv;
700		unwind(LLEAVE);
701	}
702	return rv;
703}
704
705static void
706scriptexec(struct op *tp, char **ap)
707{
708	char *shell;
709
710	shell = str_val(global("EXECSHELL"));
711	if (shell && *shell)
712		shell = search(shell, search_path, X_OK, NULL);
713	if (!shell || !*shell)
714		shell = _PATH_BSHELL;
715
716	*tp->args-- = tp->str;
717	*tp->args = shell;
718
719	execve(tp->args[0], tp->args, ap);
720
721	/* report both the program that was run and the bogus shell */
722	errorf("%s: %s: %s", tp->str, shell, strerror(errno));
723}
724
725int
726shcomexec(char **wp)
727{
728	struct tbl *tp;
729
730	tp = ktsearch(&builtins, *wp, hash(*wp));
731	if (tp == NULL)
732		internal_errorf("%s: %s", __func__, *wp);
733	return call_builtin(tp, wp);
734}
735
736/*
737 * Search function tables for a function.  If create set, a table entry
738 * is created if none is found.
739 */
740struct tbl *
741findfunc(const char *name, unsigned int h, int create)
742{
743	struct block *l;
744	struct tbl *tp = NULL;
745
746	for (l = genv->loc; l; l = l->next) {
747		tp = ktsearch(&l->funs, name, h);
748		if (tp)
749			break;
750		if (!l->next && create) {
751			tp = ktenter(&l->funs, name, h);
752			tp->flag = DEFINED;
753			tp->type = CFUNC;
754			tp->val.t = NULL;
755			break;
756		}
757	}
758	return tp;
759}
760
761/*
762 * define function.  Returns 1 if function is being undefined (t == 0) and
763 * function did not exist, returns 0 otherwise.
764 */
765int
766define(const char *name, struct op *t)
767{
768	struct tbl *tp;
769	int was_set = 0;
770
771	while (1) {
772		tp = findfunc(name, hash(name), true);
773
774		if (tp->flag & ISSET)
775			was_set = 1;
776		/* If this function is currently being executed, we zap this
777		 * table entry so findfunc() won't see it
778		 */
779		if (tp->flag & FINUSE) {
780			tp->name[0] = '\0';
781			tp->flag &= ~DEFINED; /* ensure it won't be found */
782			tp->flag |= FDELETE;
783		} else
784			break;
785	}
786
787	if (tp->flag & ALLOC) {
788		tp->flag &= ~(ISSET|ALLOC);
789		tfree(tp->val.t, tp->areap);
790	}
791
792	if (t == NULL) {		/* undefine */
793		ktdelete(tp);
794		return was_set ? 0 : 1;
795	}
796
797	tp->val.t = tcopy(t->left, tp->areap);
798	tp->flag |= (ISSET|ALLOC);
799	if (t->u.ksh_func)
800		tp->flag |= FKSH;
801
802	return 0;
803}
804
805/*
806 * add builtin
807 */
808void
809builtin(const char *name, int (*func) (char **))
810{
811	struct tbl *tp;
812	int flag;
813
814	/* see if any flags should be set for this builtin */
815	for (flag = 0; ; name++) {
816		if (*name == '=')	/* command does variable assignment */
817			flag |= KEEPASN;
818		else if (*name == '*')	/* POSIX special builtin */
819			flag |= SPEC_BI;
820		else if (*name == '+')	/* POSIX regular builtin */
821			flag |= REG_BI;
822		else
823			break;
824	}
825
826	tp = ktenter(&builtins, name, hash(name));
827	tp->flag = DEFINED | flag;
828	tp->type = CSHELL;
829	tp->val.f = func;
830}
831
832/*
833 * find command
834 * either function, hashed command, or built-in (in that order)
835 */
836struct tbl *
837findcom(const char *name, int flags)
838{
839	static struct tbl temp;
840	unsigned int h = hash(name);
841	struct tbl *tp = NULL, *tbi;
842	int insert = Flag(FTRACKALL);	/* insert if not found */
843	char *fpath;			/* for function autoloading */
844	char *npath;
845
846	if (strchr(name, '/') != NULL) {
847		insert = 0;
848		/* prevent FPATH search below */
849		flags &= ~FC_FUNC;
850		goto Search;
851	}
852	tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
853	/* POSIX says special builtins first, then functions, then
854	 * POSIX regular builtins, then search path...
855	 */
856	if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
857		tp = tbi;
858	if (!tp && (flags & FC_FUNC)) {
859		tp = findfunc(name, h, false);
860		if (tp && !(tp->flag & ISSET)) {
861			if ((fpath = str_val(global("FPATH"))) == null) {
862				tp->u.fpath = NULL;
863				tp->u2.errno_ = 0;
864			} else
865				tp->u.fpath = search(name, fpath, R_OK,
866				    &tp->u2.errno_);
867		}
868	}
869	if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
870		tp = tbi;
871	/* todo: posix says non-special/non-regular builtins must
872	 * be triggered by some user-controllable means like a
873	 * special directory in PATH.  Requires modifications to
874	 * the search() function.  Tracked aliases should be
875	 * modified to allow tracking of builtin commands.
876	 * This should be under control of the FPOSIX flag.
877	 * If this is changed, also change c_whence...
878	 */
879	if (!tp && (flags & FC_UNREGBI) && tbi)
880		tp = tbi;
881	if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
882		tp = ktsearch(&taliases, name, h);
883		if (tp && (tp->flag & ISSET) && access(tp->val.s, X_OK) != 0) {
884			if (tp->flag & ALLOC) {
885				tp->flag &= ~ALLOC;
886				afree(tp->val.s, APERM);
887			}
888			tp->flag &= ~ISSET;
889		}
890	}
891
892  Search:
893	if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) &&
894	    (flags & FC_PATH)) {
895		if (!tp) {
896			if (insert && !(flags & FC_DEFPATH)) {
897				tp = ktenter(&taliases, name, h);
898				tp->type = CTALIAS;
899			} else {
900				tp = &temp;
901				tp->type = CEXEC;
902			}
903			tp->flag = DEFINED;	/* make ~ISSET */
904		}
905		npath = search(name, flags & FC_DEFPATH ? def_path :
906		    search_path, X_OK, &tp->u2.errno_);
907		if (npath) {
908			if (tp == &temp) {
909				tp->val.s = npath;
910			} else {
911				tp->val.s = str_save(npath, APERM);
912				if (npath != name)
913					afree(npath, ATEMP);
914			}
915			tp->flag |= ISSET|ALLOC;
916		} else if ((flags & FC_FUNC) &&
917		    (fpath = str_val(global("FPATH"))) != null &&
918		    (npath = search(name, fpath, R_OK,
919		    &tp->u2.errno_)) != NULL) {
920			/* An undocumented feature of at&t ksh is that it
921			 * searches FPATH if a command is not found, even
922			 * if the command hasn't been set up as an autoloaded
923			 * function (ie, no typeset -uf).
924			 */
925			tp = &temp;
926			tp->type = CFUNC;
927			tp->flag = DEFINED; /* make ~ISSET */
928			tp->u.fpath = npath;
929		}
930	}
931	return tp;
932}
933
934/*
935 * flush executable commands with relative paths
936 */
937void
938flushcom(int all)	/* just relative or all */
939{
940	struct tbl *tp;
941	struct tstate ts;
942
943	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
944		if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
945			if (tp->flag&ALLOC) {
946				tp->flag &= ~(ALLOC|ISSET);
947				afree(tp->val.s, APERM);
948			}
949			tp->flag &= ~ISSET;
950		}
951}
952
953/* Check if path is something we want to find.  Returns -1 for failure. */
954int
955search_access(const char *path, int mode,
956    int *errnop)	/* set if candidate found, but not suitable */
957{
958	int ret, err = 0;
959	struct stat statb;
960
961	if (stat(path, &statb) == -1)
962		return -1;
963	ret = access(path, mode);
964	if (ret == -1)
965		err = errno; /* File exists, but we can't access it */
966	else if (mode == X_OK && (!S_ISREG(statb.st_mode) ||
967	    !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) {
968	    /* This 'cause access() says root can execute everything */
969		ret = -1;
970		err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
971	}
972	if (err && errnop && !*errnop)
973		*errnop = err;
974	return ret;
975}
976
977/*
978 * search for command with PATH
979 */
980char *
981search(const char *name, const char *path,
982    int mode,		/* R_OK or X_OK */
983    int *errnop)	/* set if candidate found, but not suitable */
984{
985	const char *sp, *p;
986	char *xp;
987	XString xs;
988	int namelen;
989
990	if (errnop)
991		*errnop = 0;
992	if (strchr(name, '/')) {
993		if (search_access(name, mode, errnop) == 0)
994			return (char *) name;
995		return NULL;
996	}
997
998	namelen = strlen(name) + 1;
999	Xinit(xs, xp, 128, ATEMP);
1000
1001	sp = path;
1002	while (sp != NULL) {
1003		xp = Xstring(xs, xp);
1004		if (!(p = strchr(sp, ':')))
1005			p = sp + strlen(sp);
1006		if (p != sp) {
1007			XcheckN(xs, xp, p - sp);
1008			memcpy(xp, sp, p - sp);
1009			xp += p - sp;
1010			*xp++ = '/';
1011		}
1012		sp = p;
1013		XcheckN(xs, xp, namelen);
1014		memcpy(xp, name, namelen);
1015		if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1016			return Xclose(xs, xp + namelen);
1017		if (*sp++ == '\0')
1018			sp = NULL;
1019	}
1020	Xfree(xs, xp);
1021	return NULL;
1022}
1023
1024static int
1025call_builtin(struct tbl *tp, char **wp)
1026{
1027	int rv;
1028
1029	builtin_argv0 = wp[0];
1030	builtin_flag = tp->flag;
1031	shf_reopen(1, SHF_WR, shl_stdout);
1032	shl_stdout_ok = 1;
1033	ksh_getopt_reset(&builtin_opt, GF_ERROR);
1034	rv = (*tp->val.f)(wp);
1035	shf_flush(shl_stdout);
1036	shl_stdout_ok = 0;
1037	builtin_flag = 0;
1038	builtin_argv0 = NULL;
1039	return rv;
1040}
1041
1042/*
1043 * set up redirection, saving old fd's in e->savefd
1044 */
1045static int
1046iosetup(struct ioword *iop, struct tbl *tp)
1047{
1048	int u = -1;
1049	char *cp = iop->name;
1050	int iotype = iop->flag & IOTYPE;
1051	int do_open = 1, do_close = 0, flags = 0;
1052	struct ioword iotmp;
1053	struct stat statb;
1054
1055	if (iotype != IOHERE)
1056		cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
1057
1058	/* Used for tracing and error messages to print expanded cp */
1059	iotmp = *iop;
1060	iotmp.name = (iotype == IOHERE) ? NULL : cp;
1061	iotmp.flag |= IONAMEXP;
1062
1063	if (Flag(FXTRACE))
1064		shellf("%s%s\n",
1065		    PS4_SUBSTITUTE(str_val(global("PS4"))),
1066		    snptreef(NULL, 32, "%R", &iotmp));
1067
1068	switch (iotype) {
1069	case IOREAD:
1070		flags = O_RDONLY;
1071		break;
1072
1073	case IOCAT:
1074		flags = O_WRONLY | O_APPEND | O_CREAT;
1075		break;
1076
1077	case IOWRITE:
1078		flags = O_WRONLY | O_CREAT | O_TRUNC;
1079		/* The stat() is here to allow redirections to
1080		 * things like /dev/null without error.
1081		 */
1082		if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
1083		    (stat(cp, &statb) == -1 || S_ISREG(statb.st_mode)))
1084			flags |= O_EXCL;
1085		break;
1086
1087	case IORDWR:
1088		flags = O_RDWR | O_CREAT;
1089		break;
1090
1091	case IOHERE:
1092		do_open = 0;
1093		/* herein() returns -2 if error has been printed */
1094		u = herein(iop->heredoc, iop->flag & IOEVAL);
1095		/* cp may have wrong name */
1096		break;
1097
1098	case IODUP:
1099	    {
1100		const char *emsg;
1101
1102		do_open = 0;
1103		if (*cp == '-' && !cp[1]) {
1104			u = 1009;	 /* prevent error return below */
1105			do_close = 1;
1106		} else if ((u = check_fd(cp,
1107		    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
1108		    &emsg)) < 0) {
1109			warningf(true, "%s: %s",
1110			    snptreef(NULL, 32, "%R", &iotmp), emsg);
1111			return -1;
1112		}
1113		if (u == iop->unit)
1114			return 0;		/* "dup from" == "dup to" */
1115		break;
1116	    }
1117	}
1118
1119	if (do_open) {
1120		if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
1121			warningf(true, "%s: restricted", cp);
1122			return -1;
1123		}
1124		u = open(cp, flags, 0666);
1125	}
1126	if (u < 0) {
1127		/* herein() may already have printed message */
1128		if (u == -1)
1129			warningf(true, "cannot %s %s: %s",
1130			    iotype == IODUP ? "dup" :
1131			    (iotype == IOREAD || iotype == IOHERE) ?
1132			    "open" : "create", cp, strerror(errno));
1133		return -1;
1134	}
1135	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
1136	if (genv->savefd[iop->unit] == 0) {
1137		/* If these are the same, it means unit was previously closed */
1138		if (u == iop->unit)
1139			genv->savefd[iop->unit] = -1;
1140		else
1141			/* c_exec() assumes e->savefd[fd] set for any
1142			 * redirections.  Ask savefd() not to close iop->unit;
1143			 * this allows error messages to be seen if iop->unit
1144			 * is 2; also means we can't lose the fd (eg, both
1145			 * dup2 below and dup2 in restfd() failing).
1146			 */
1147			genv->savefd[iop->unit] = savefd(iop->unit);
1148	}
1149
1150	if (do_close)
1151		close(iop->unit);
1152	else if (u != iop->unit) {
1153		if (ksh_dup2(u, iop->unit, true) < 0) {
1154			warningf(true,
1155			    "could not finish (dup) redirection %s: %s",
1156			    snptreef(NULL, 32, "%R", &iotmp),
1157			    strerror(errno));
1158			if (iotype != IODUP)
1159				close(u);
1160			return -1;
1161		}
1162		if (iotype != IODUP)
1163			close(u);
1164		/* Touching any co-process fd in an empty exec
1165		 * causes the shell to close its copies
1166		 */
1167		else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
1168			if (iop->flag & IORDUP)	/* possible exec <&p */
1169				coproc_read_close(u);
1170			else			/* possible exec >&p */
1171				coproc_write_close(u);
1172		}
1173	}
1174	if (u == 2) /* Clear any write errors */
1175		shf_reopen(2, SHF_WR, shl_out);
1176	return 0;
1177}
1178
1179/*
1180 * open here document temp file.
1181 * if unquoted here, expand here temp file into second temp file.
1182 */
1183static int
1184herein(const char *content, int sub)
1185{
1186	volatile int fd = -1;
1187	struct source *s, *volatile osource;
1188	struct shf *volatile shf;
1189	struct temp *h;
1190	int i;
1191
1192	/* ksh -c 'cat << EOF' can cause this... */
1193	if (content == NULL) {
1194		warningf(true, "here document missing");
1195		return -2; /* special to iosetup(): don't print error */
1196	}
1197
1198	/* Create temp file to hold content (done before newenv so temp
1199	 * doesn't get removed too soon).
1200	 */
1201	h = maketemp(ATEMP, TT_HEREDOC_EXP, &genv->temps);
1202	if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY)) == -1) {
1203		warningf(true, "can't %s temporary file %s: %s",
1204		    !shf ? "create" : "open",
1205		    h->name, strerror(errno));
1206		if (shf)
1207			shf_close(shf);
1208		return -2 /* special to iosetup(): don't print error */;
1209	}
1210
1211	osource = source;
1212	newenv(E_ERRH);
1213	i = sigsetjmp(genv->jbuf, 0);
1214	if (i) {
1215		source = osource;
1216		quitenv(shf);
1217		close(fd);
1218		return -2; /* special to iosetup(): don't print error */
1219	}
1220	if (sub) {
1221		/* Do substitutions on the content of heredoc */
1222		s = pushs(SSTRING, ATEMP);
1223		s->start = s->str = content;
1224		source = s;
1225		if (yylex(ONEWORD|HEREDOC) != LWORD)
1226			internal_errorf("%s: yylex", __func__);
1227		source = osource;
1228		shf_puts(evalstr(yylval.cp, 0), shf);
1229	} else
1230		shf_puts(content, shf);
1231
1232	quitenv(NULL);
1233
1234	if (shf_close(shf) == EOF) {
1235		close(fd);
1236		warningf(true, "error writing %s: %s", h->name,
1237		    strerror(errno));
1238		return -2; /* special to iosetup(): don't print error */
1239	}
1240
1241	return fd;
1242}
1243
1244/*
1245 *	ksh special - the select command processing section
1246 *	print the args in column form - assuming that we can
1247 */
1248static char *
1249do_selectargs(char **ap, bool print_menu)
1250{
1251	static const char *const read_args[] = {
1252		"read", "-r", "REPLY", NULL
1253	};
1254	const char *errstr;
1255	char *s;
1256	int i, argct;
1257
1258	for (argct = 0; ap[argct]; argct++)
1259		;
1260	while (1) {
1261		/* Menu is printed if
1262		 *	- this is the first time around the select loop
1263		 *	- the user enters a blank line
1264		 *	- the REPLY parameter is empty
1265		 */
1266		if (print_menu || !*str_val(global("REPLY")))
1267			pr_menu(ap);
1268		shellf("%s", str_val(global("PS3")));
1269		if (call_builtin(findcom("read", FC_BI), (char **) read_args))
1270			return NULL;
1271		s = str_val(global("REPLY"));
1272		if (*s) {
1273			i = strtonum(s, 1, argct, &errstr);
1274			if (errstr)
1275				return null;
1276			return ap[i - 1];
1277		}
1278		print_menu = 1;
1279	}
1280}
1281
1282struct select_menu_info {
1283	char	*const *args;
1284	int	arg_width;
1285	int	num_width;
1286};
1287
1288static char *select_fmt_entry(void *arg, int i, char *buf, int buflen);
1289
1290/* format a single select menu item */
1291static char *
1292select_fmt_entry(void *arg, int i, char *buf, int buflen)
1293{
1294	struct select_menu_info *smi = (struct select_menu_info *) arg;
1295
1296	shf_snprintf(buf, buflen, "%*d) %s",
1297	    smi->num_width, i + 1, smi->args[i]);
1298	return buf;
1299}
1300
1301/*
1302 *	print a select style menu
1303 */
1304int
1305pr_menu(char *const *ap)
1306{
1307	struct select_menu_info smi;
1308	char *const *pp;
1309	int nwidth, dwidth;
1310	int i, n;
1311
1312	/* Width/column calculations were done once and saved, but this
1313	 * means select can't be used recursively so we re-calculate each
1314	 * time (could save in a structure that is returned, but its probably
1315	 * not worth the bother).
1316	 */
1317
1318	/*
1319	 * get dimensions of the list
1320	 */
1321	for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1322		i = strlen(*pp);
1323		nwidth = (i > nwidth) ? i : nwidth;
1324	}
1325	/*
1326	 * we will print an index of the form
1327	 *	%d)
1328	 * in front of each entry
1329	 * get the max width of this
1330	 */
1331	for (i = n, dwidth = 1; i >= 10; i /= 10)
1332		dwidth++;
1333
1334	smi.args = ap;
1335	smi.arg_width = nwidth;
1336	smi.num_width = dwidth;
1337	print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
1338	    dwidth + nwidth + 2, 1);
1339
1340	return n;
1341}
1342
1343/* XXX: horrible kludge to fit within the framework */
1344
1345static char *plain_fmt_entry(void *arg, int i, char *buf, int buflen);
1346
1347static char *
1348plain_fmt_entry(void *arg, int i, char *buf, int buflen)
1349{
1350	shf_snprintf(buf, buflen, "%s", ((char *const *)arg)[i]);
1351	return buf;
1352}
1353
1354int
1355pr_list(char *const *ap)
1356{
1357	char *const *pp;
1358	int nwidth;
1359	int i, n;
1360
1361	for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1362		i = strlen(*pp);
1363		nwidth = (i > nwidth) ? i : nwidth;
1364	}
1365	print_columns(shl_out, n, plain_fmt_entry, (void *) ap, nwidth + 1, 0);
1366
1367	return n;
1368}
1369
1370/*
1371 *	[[ ... ]] evaluation routines
1372 */
1373
1374extern const char *const dbtest_tokens[];
1375extern const char db_close[];
1376
1377/* Test if the current token is a whatever.  Accepts the current token if
1378 * it is.  Returns 0 if it is not, non-zero if it is (in the case of
1379 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
1380 */
1381static int
1382dbteste_isa(Test_env *te, Test_meta meta)
1383{
1384	int ret = 0;
1385	int uqword;
1386	char *p;
1387
1388	if (!*te->pos.wp)
1389		return meta == TM_END;
1390
1391	/* unquoted word? */
1392	for (p = *te->pos.wp; *p == CHAR; p += 2)
1393		;
1394	uqword = *p == EOS;
1395
1396	if (meta == TM_UNOP || meta == TM_BINOP) {
1397		if (uqword) {
1398			char buf[8];	/* longer than the longest operator */
1399			char *q = buf;
1400			for (p = *te->pos.wp;
1401			    *p == CHAR && q < &buf[sizeof(buf) - 1]; p += 2)
1402				*q++ = p[1];
1403			*q = '\0';
1404			ret = (int) test_isop(te, meta, buf);
1405		}
1406	} else if (meta == TM_END)
1407		ret = 0;
1408	else
1409		ret = uqword &&
1410		    strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
1411
1412	/* Accept the token? */
1413	if (ret)
1414		te->pos.wp++;
1415
1416	return ret;
1417}
1418
1419static const char *
1420dbteste_getopnd(Test_env *te, Test_op op, int do_eval)
1421{
1422	char *s = *te->pos.wp;
1423
1424	if (!s)
1425		return NULL;
1426
1427	te->pos.wp++;
1428
1429	if (!do_eval)
1430		return null;
1431
1432	if (op == TO_STEQL || op == TO_STNEQ)
1433		s = evalstr(s, DOTILDE | DOPAT);
1434	else
1435		s = evalstr(s, DOTILDE);
1436
1437	return s;
1438}
1439
1440static int
1441dbteste_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
1442    int do_eval)
1443{
1444	return test_eval(te, op, opnd1, opnd2, do_eval);
1445}
1446
1447static void
1448dbteste_error(Test_env *te, int offset, const char *msg)
1449{
1450	te->flags |= TEF_ERROR;
1451	internal_warningf("%s: %s (offset %d)", __func__, msg, offset);
1452}