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