GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/exec.c Lines: 505 711 71.0 %
Date: 2017-11-07 Branches: 369 528 69.9 %

Line Branch Exec Source
1
/*	$OpenBSD: exec.c,v 1.68 2016/12/11 17:49:19 millert 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,		/* 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
34234794
	int i, dummy = 0, save_xerrok = 0;
49
34234794
	volatile int rv = 0;
50
34234794
	int pv[2];
51
34234794
	char ** volatile ap;
52
	char *s, *cp;
53
	struct ioword **iowp;
54
	struct tbl *tp = NULL;
55
56
34234794
	if (t == NULL)
57
1576980
		return 0;
58
59
	/* Caller doesn't care if XERROK should propagate. */
60
32657814
	if (xerrok == NULL)
61
21168322
		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

39136982
	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
72
1499984
		return exchild(t, flags & ~XTIME, xerrok, -1); /* run in sub-process */
73
74
31157830
	newenv(E_EXEC);
75
31157830
	if (trap)
76
4093409
		runtraps(0);
77
78
31157782
	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
18264028
		subst_exstat = 0;
83
84
18264028
		current_lineno = t->lineno;	/* for $LINENO */
85
86
		/* POSIX says expand command words first, then redirections,
87
		 * and assignments last..
88
		 */
89
18264028
		ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
90
18264028
		if (flags & XTIME)
91
			/* Allow option parsing (bizarre, but POSIX) */
92
2328
			timex_hook(t, &ap);
93

18304852
		if (Flag(FXTRACE) && ap[0]) {
94
40310
			shf_fprintf(shl_out, "%s",
95
40310
				PS4_SUBSTITUTE(str_val(global("PS4"))));
96
255152
			for (i = 0; ap[i]; i++)
97
174532
				shf_fprintf(shl_out, "%s%s", ap[i],
98
87266
				    ap[i + 1] ? " " : "\n");
99
40310
			shf_flush(shl_out);
100
40310
		}
101
18264028
		if (ap[0])
102
10958095
			tp = findcom(ap[0], FC_BI|FC_FUNC);
103
	}
104
31155585
	flags &= ~XTIME;
105
106

88461614
	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
107
3504048
		genv->savefd = areallocarray(NULL, NUFILE, sizeof(short), ATEMP);
108
		/* initialize to not redirected */
109
3504048
		memset(genv->savefd, 0, NUFILE * sizeof(short));
110
3504048
	}
111
112
	/* do redirection, to be restored in quitenv() */
113
31155585
	if (t->ioact != NULL)
114
6701558
		for (iowp = t->ioact; *iowp != NULL; iowp++) {
115
1849686
			if (iosetup(*iowp, tp) < 0) {
116
				exstat = rv = 1;
117
				/* Redirection failures for special commands
118
				 * cause (non-interactive) shell to exit.
119
				 */
120
				if (tp && tp->type == CSHELL &&
121
				    (tp->flag & SPEC_BI))
122
					errorf(NULL);
123
				/* Deal with FERREXIT, quitenv(), etc. */
124
				goto Break;
125
			}
126
		}
127
128





72493355
	switch (t->type) {
129
	case TCOM:
130
18263585
		rv = comexec(t, tp, ap, flags, xerrok);
131
18263585
		break;
132
133
	case TPAREN:
134
257739
		rv = execute(t->left, flags|XFORK, xerrok);
135
257739
		break;
136
137
	case TPIPE:
138
2002955
		flags |= XFORK;
139
2002955
		flags &= ~XEXEC;
140
2002955
		genv->savefd[0] = savefd(0);
141
2002955
		genv->savefd[1] = savefd(1);
142
9392896
		while (t->type == TPIPE) {
143
2723607
			openpipe(pv);
144
2723607
			(void) ksh_dup2(pv[1], 1, false); /* stdout of curr */
145
			/* Let exchild() close pv[0] in child
146
			 * (if this isn't done, commands like
147
			 *    (: ; cat /etc/termcap) | sleep 1
148
			 *  will hang forever).
149
			 */
150
2723607
			exchild(t->left, flags|XPIPEO|XCCLOSE, NULL, pv[0]);
151
2723607
			(void) ksh_dup2(pv[0], 0, false); /* stdin of next */
152
2723607
			closepipe(pv);
153
2723607
			flags |= XPIPEI;
154
2723607
			t = t->right;
155
		}
156
1942256
		restfd(1, genv->savefd[1]); /* stdout of last */
157
1942256
		genv->savefd[1] = 0; /* no need to re-restore this */
158
		/* Let exchild() close 0 in parent, after fork, before wait */
159
1942256
		i = exchild(t, flags|XPCLOSE, xerrok, 0);
160

3884442
		if (!(flags&XBGND) && !(flags&XXCOM))
161
213852
			rv = i;
162
		break;
163
164
	case TLIST:
165
28132548
		while (t->type == TLIST) {
166
12644068
			execute(t->left, flags & XERROK, NULL);
167
12644068
			t = t->right;
168
		}
169
2844412
		rv = execute(t, flags & XERROK, xerrok);
170
2844412
		break;
171
172
	case TCOPROC:
173
	    {
174
		sigset_t	omask;
175
176
		/* Block sigchild as we are using things changed in the
177
		 * signal handler
178
		 */
179
		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
180
		genv->type = E_ERRH;
181
		i = sigsetjmp(genv->jbuf, 0);
182
		if (i) {
183
			sigprocmask(SIG_SETMASK, &omask, NULL);
184
			quitenv(NULL);
185
			unwind(i);
186
			/* NOTREACHED */
187
		}
188
		/* Already have a (live) co-process? */
189
		if (coproc.job && coproc.write >= 0)
190
			errorf("coprocess already exists");
191
192
		/* Can we re-use the existing co-process pipe? */
193
		coproc_cleanup(true);
194
195
		/* do this before opening pipes, in case these fail */
196
		genv->savefd[0] = savefd(0);
197
		genv->savefd[1] = savefd(1);
198
199
		openpipe(pv);
200
		if (pv[0] != 0) {
201
			ksh_dup2(pv[0], 0, false);
202
			close(pv[0]);
203
		}
204
		coproc.write = pv[1];
205
		coproc.job = NULL;
206
207
		if (coproc.readw >= 0)
208
			ksh_dup2(coproc.readw, 1, false);
209
		else {
210
			openpipe(pv);
211
			coproc.read = pv[0];
212
			ksh_dup2(pv[1], 1, false);
213
			coproc.readw = pv[1];	 /* closed before first read */
214
			coproc.njobs = 0;
215
			/* create new coprocess id */
216
			++coproc.id;
217
		}
218
		sigprocmask(SIG_SETMASK, &omask, NULL);
219
		genv->type = E_EXEC; /* no more need for error handler */
220
221
		/* exchild() closes coproc.* in child after fork,
222
		 * will also increment coproc.njobs when the
223
		 * job is actually created.
224
		 */
225
		flags &= ~XEXEC;
226
		exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
227
		    NULL, coproc.readw);
228
		break;
229
	    }
230
231
	case TASYNC:
232
		/* XXX non-optimal, I think - "(foo &)", forks for (),
233
		 * forks again for async...  parent should optimize
234
		 * this to "foo &"...
235
		 */
236
2819
		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
237
2819
		break;
238
239
	case TOR:
240
	case TAND:
241
2044471
		rv = execute(t->left, XERROK, xerrok);
242
2044471
		if ((rv == 0) == (t->type == TAND))
243
894724
			rv = execute(t->right, flags & XERROK, xerrok);
244
		else {
245
1149747
			flags |= XERROK;
246
1149747
			*xerrok = 1;
247
		}
248
		break;
249
250
	case TBANG:
251
49874
		rv = !execute(t->right, XERROK, xerrok);
252
49874
		flags |= XERROK;
253
49874
		*xerrok = 1;
254
49874
		break;
255
256
	case TDBRACKET:
257
	    {
258
215512
		Test_env te;
259
260
215512
		te.flags = TEF_DBRACKET;
261
215512
		te.pos.wp = t->args;
262
215512
		te.isa = dbteste_isa;
263
215512
		te.getopnd = dbteste_getopnd;
264
215512
		te.eval = dbteste_eval;
265
215512
		te.error = dbteste_error;
266
267
215512
		rv = test_parse(&te);
268
		break;
269
215512
	    }
270
271
	case TFOR:
272
	case TSELECT:
273
	    {
274
190012
		volatile bool is_first = true;
275
569567
		ap = (t->vars != NULL) ? eval(t->vars, DOBLANK|DOGLOB|DOTILDE) :
276
13032
		    genv->loc->argv + 1;
277
189543
		genv->type = E_LOOP;
278
189543
		while (1) {
279
332525
			i = sigsetjmp(genv->jbuf, 0);
280
332525
			if (!i)
281
				break;
282
87874
			if ((genv->flags&EF_BRKCONT_PASS) ||
283
80898
			    (i != LBREAK && i != LCONTIN)) {
284
				quitenv(NULL);
285
				unwind(i);
286
80708
			} else if (i == LBREAK) {
287
25600
				rv = 0;
288
25600
				goto Break;
289
			}
290
		}
291
244651
		rv = 0; /* in case of a continue */
292
244651
		if (t->type == TFOR) {
293
244651
			save_xerrok = *xerrok;
294
2102397
			while (*ap != NULL) {
295
853034
				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
296
				/* undo xerrok in all iterations except the
297
				 * last */
298
853034
				*xerrok = save_xerrok;
299
853034
				rv = execute(t->left, flags & XERROK, xerrok);
300
			}
301
			/* ripple xerrok set at final iteration */
302
		} else { /* TSELECT */
303
			for (;;) {
304
				if (!(cp = do_selectargs(ap, is_first))) {
305
					rv = 1;
306
					break;
307
				}
308
				is_first = false;
309
				setstr(global(t->str), cp, KSH_UNWIND_ERROR);
310
				rv = execute(t->left, flags & XERROK, xerrok);
311
			}
312
		}
313
829087
	    }
314
		break;
315
316
	case TWHILE:
317
	case TUNTIL:
318
112367
		genv->type = E_LOOP;
319
112367
		while (1) {
320
148344
			i = sigsetjmp(genv->jbuf, 0);
321
148344
			if (!i)
322
				break;
323
19010
			if ((genv->flags&EF_BRKCONT_PASS) ||
324
19010
			    (i != LBREAK && i != LCONTIN)) {
325
				quitenv(NULL);
326
				unwind(i);
327
18907
			} else if (i == LBREAK) {
328
1940
				rv = 0;
329
1940
				goto Break;
330
			}
331
		}
332
129334
		rv = 0; /* in case of a continue */
333
746054
		while ((execute(t->left, XERROK, NULL) == 0) == (t->type == TWHILE))
334
254577
			rv = execute(t->right, flags & XERROK, xerrok);
335
		break;
336
337
	case TIF:
338
	case TELIF:
339
2472191
		if (t->right == NULL)
340
			break;	/* should be error */
341
7343898
		rv = execute(t->left, XERROK, NULL) == 0 ?
342
688823
		    execute(t->right->left, flags & XERROK, xerrok) :
343
1780330
		    execute(t->right->right, flags & XERROK, xerrok);
344
2405592
		break;
345
346
	case TCASE:
347
500837
		cp = evalstr(t->str, DOTILDE);
348

5310373
		for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
349
17655906
			for (ap = t->vars; *ap; ap++) {
350

15033880
				if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
351
7516940
				    gmatch(cp, s, false))
352
					goto Found;
353
			}
354
		}
355
		break;
356
	  Found:
357
375729
		rv = execute(t->left, flags & XERROK, xerrok);
358
375729
		break;
359
360
	case TBRACE:
361
1788699
		rv = execute(t->left, flags & XERROK, xerrok);
362
1788699
		break;
363
364
	case TFUNCT:
365
83002
		rv = define(t->str, t);
366
83002
		break;
367
368
	case TTIME:
369
		/* Clear XEXEC so nested execute() call doesn't exit
370
		 * (allows "ls -l | time grep foo").
371
		 */
372
2328
		rv = timex(t, flags & ~XEXEC, xerrok);
373
2328
		break;
374
375
	case TEXEC:		/* an eval'd TCOM */
376
		s = t->args[0];
377
		ap = makenv();
378
		restoresigs();
379
		cleanup_proc_env();
380
		execve(t->str, t->args, ap);
381
		if (errno == ENOEXEC)
382
			scriptexec(t, ap);
383
		else
384
			errorf("%s: %s", s, strerror(errno));
385
	}
386
    Break:
387
29401921
	exstat = rv;
388
389
29401921
	quitenv(NULL);		/* restores IO */
390
29401921
	if ((flags&XEXEC))
391
		unwind(LEXIT);	/* exit child */
392

33434871
	if (rv != 0 && !(flags & XERROK) && !*xerrok) {
393
103593
		trapsig(SIGERR_);
394
103593
		if (Flag(FERREXIT))
395
			unwind(LERROR);
396
	}
397
29394199
	return rv;
398
32449897
}
399
400
/*
401
 * execute simple command
402
 */
403
404
static int
405
comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
406
    volatile int *xerrok)
407
{
408
	int i;
409
18263585
	volatile int rv = 0;
410
	char *cp;
411
	char **lastp;
412
	static struct op texec; /* Must be static (XXX but why?) */
413
	int type_flags;
414
	int keepasn_ok;
415
	int fcflags = FC_BI|FC_FUNC|FC_PATH;
416
	int bourne_function_call = 0;
417
418
	/* snag the last argument for $_ XXX not the same as at&t ksh,
419
	 * which only seems to set $_ after a newline (but not in
420
	 * functions/dot scripts, but in interactive and script) -
421
	 * perhaps save last arg here and set it in shell()?.
422
	 */
423

19500480
	if (!Flag(FSH) && Flag(FTALKING) && *(lastp = ap)) {
424
47973
		while (*++lastp)
425
			;
426
		/* setstr() can't fail here */
427
4085
		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
428
		    KSH_RETURN_ERROR);
429
4085
	}
430
431
	/* Deal with the shell builtins builtin, exec and command since
432
	 * they can be followed by other commands.  This must be done before
433
	 * we know if we should create a local block, which must be done
434
	 * before we can do a path search (in case the assignments change
435
	 * PATH).
436
	 * Odd cases:
437
	 *   FOO=bar exec > /dev/null		FOO is kept but not exported
438
	 *   FOO=bar exec foobar		FOO is exported
439
	 *   FOO=bar command exec > /dev/null	FOO is neither kept nor exported
440
	 *   FOO=bar command			FOO is neither kept nor exported
441
	 *   PATH=... foobar			use new PATH in foobar search
442
	 */
443
	keepasn_ok = 1;
444

46441005
	while (tp && tp->type == CSHELL) {
445
		fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
446
8687904
		if (tp->val.f == c_builtin) {
447
			if ((cp = *++ap) == NULL) {
448
				tp = NULL;
449
				break;
450
			}
451
			tp = findcom(cp, FC_BI);
452
			if (tp == NULL)
453
				errorf("builtin: %s: not a builtin", cp);
454
			continue;
455
8687904
		} else if (tp->val.f == c_exec) {
456
68508
			if (ap[1] == NULL)
457
				break;
458
25
			ap++;
459
25
			flags |= XEXEC;
460
8619421
		} else if (tp->val.f == c_command) {
461
			int optc, saw_p = 0;
462
463
			/* Ugly dealing with options in two places (here and
464
			 * in c_command(), but such is life)
465
			 */
466
600
			ksh_getopt_reset(&builtin_opt, 0);
467
1800
			while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
468
				saw_p = 1;
469
600
			if (optc != EOF)
470
600
				break;	/* command -vV or something */
471
			/* don't look for functions */
472
			fcflags = FC_BI|FC_PATH;
473
			if (saw_p) {
474
				if (Flag(FRESTRICTED)) {
475
					warningf(true,
476
					    "command -p: restricted");
477
					rv = 1;
478
					goto Leave;
479
				}
480
				fcflags |= FC_DEFPATH;
481
			}
482
			ap += builtin_opt.optind;
483
			/* POSIX says special builtins lose their status
484
			 * if accessed using command.
485
			 */
486
			keepasn_ok = 0;
487
			if (!ap[0]) {
488
				/* ensure command with no args exits with 0 */
489
				subst_exstat = 0;
490
				break;
491
			}
492
		} else
493
			break;
494
25
		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
495
	}
496


57398582
	if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
497
9877779
		type_flags = 0;
498
	else {
499
		/* create new variable/function block */
500
8385806
		newblock();
501
		/* ksh functions don't keep assignments, POSIX functions do. */
502


25339407
		if (keepasn_ok && tp && tp->type == CFUNC &&
503
1225881
		    !(tp->flag & FKSH)) {
504
			bourne_function_call = 1;
505
			type_flags = 0;
506
1220949
		} else
507
			type_flags = LOCAL|LOCAL_COPY|EXPORT;
508
	}
509
18263585
	if (Flag(FEXPORT))
510
		type_flags |= EXPORT;
511
51398292
	for (i = 0; t->vars[i]; i++) {
512
7435669
		cp = evalstr(t->vars[i], DOASNTILDE);
513
7435669
		if (Flag(FXTRACE)) {
514
472
			if (i == 0)
515
472
				shf_fprintf(shl_out, "%s",
516
472
				    PS4_SUBSTITUTE(str_val(global("PS4"))));
517
472
			shf_fprintf(shl_out, "%s%s", cp,
518
472
			    t->vars[i + 1] ? " " : "\n");
519
472
			if (!t->vars[i + 1])
520
472
				shf_flush(shl_out);
521
		}
522
7435561
		typeset(cp, type_flags, 0, 0, 0);
523

7435611
		if (bourne_function_call && !(type_flags & EXPORT))
524
50
			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
525
	}
526
527
18238512
	if ((cp = *ap) == NULL) {
528
7280885
		rv = subst_exstat;
529
7280885
		goto Leave;
530
10957627
	} else if (!tp) {
531

1043867
		if (Flag(FRESTRICTED) && strchr(cp, '/')) {
532
			warningf(true, "%s: restricted", cp);
533
			rv = 1;
534
			goto Leave;
535
		}
536
1043867
		tp = findcom(cp, fcflags);
537
1043867
	}
538
539

27287168
	switch (tp->type) {
540
	case CSHELL:			/* shell built-in */
541
8687879
		rv = call_builtin(tp, ap);
542
8687879
		break;
543
544
	case CFUNC:			/* function call */
545
	    {
546
1225881
		volatile int old_xflag, old_inuse;
547
1225881
		const char *volatile old_kshname;
548
549
1225881
		if (!(tp->flag & ISSET)) {
550
			struct tbl *ftp;
551
552
			if (!tp->u.fpath) {
553
				if (tp->u2.errno_) {
554
					warningf(true,
555
					    "%s: can't find function "
556
					    "definition file - %s",
557
					    cp, strerror(tp->u2.errno_));
558
					rv = 126;
559
				} else {
560
					warningf(true,
561
					    "%s: can't find function "
562
					    "definition file", cp);
563
					rv = 127;
564
				}
565
				break;
566
			}
567
			if (include(tp->u.fpath, 0, NULL, 0) < 0) {
568
				warningf(true,
569
				    "%s: can't open function definition file %s - %s",
570
				    cp, tp->u.fpath, strerror(errno));
571
				rv = 127;
572
				break;
573
			}
574
			if (!(ftp = findfunc(cp, hash(cp), false)) ||
575
			    !(ftp->flag & ISSET)) {
576
				warningf(true,
577
				    "%s: function not defined by %s",
578
				    cp, tp->u.fpath);
579
				rv = 127;
580
				break;
581
			}
582
			tp = ftp;
583
		}
584
585
		/* ksh functions set $0 to function name, POSIX functions leave
586
		 * $0 unchanged.
587
		 */
588
1225881
		old_kshname = kshname;
589
1225881
		if (tp->flag & FKSH)
590
4932
			kshname = ap[0];
591
		else
592
1220949
			ap[0] = (char *) kshname;
593
1225881
		genv->loc->argv = ap;
594
11937366
		for (i = 0; *ap++ != NULL; i++)
595
			;
596
1225881
		genv->loc->argc = i - 1;
597
		/* ksh-style functions handle getopts sanely,
598
		 * bourne/posix functions are insane...
599
		 */
600
1225881
		if (tp->flag & FKSH) {
601
4932
			genv->loc->flags |= BF_DOGETOPTS;
602
4932
			genv->loc->getopts_state = user_opt;
603
4932
			getopts_reset(1);
604
4932
		}
605
606
1527738
		old_xflag = Flag(FXTRACE);
607
1527738
		Flag(FXTRACE) = tp->flag & TRACE ? true : false;
608
609
1527738
		old_inuse = tp->flag & FINUSE;
610
1527738
		tp->flag |= FINUSE;
611
612
1527738
		genv->type = E_FUNC;
613
1527738
		i = sigsetjmp(genv->jbuf, 0);
614
1527738
		if (i == 0) {
615
			/* seems odd to pass XERROK here, but at&t ksh does */
616
1225881
			exstat = execute(tp->val.t, flags & XERROK, xerrok);
617
			i = LRETURN;
618
1225881
		}
619
1190229
		kshname = old_kshname;
620
1190229
		Flag(FXTRACE) = old_xflag;
621
1190229
		tp->flag = (tp->flag & ~FINUSE) | old_inuse;
622
		/* Were we deleted while executing?  If so, free the execution
623
		 * tree.  todo: Unfortunately, the table entry is never re-used
624
		 * until the lookup table is expanded.
625
		 */
626
1190229
		if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
627
			if (tp->flag & ALLOC) {
628
				tp->flag &= ~ALLOC;
629
				tfree(tp->val.t, tp->areap);
630
			}
631
			tp->flag = 0;
632
		}
633

1190229
		switch (i) {
634
		case LRETURN:
635
		case LERROR:
636
1189452
			rv = exstat;
637
1189452
			break;
638
		case LINTR:
639
		case LEXIT:
640
		case LLEAVE:
641
		case LSHELL:
642
			quitenv(NULL);
643
			unwind(i);
644
			/* NOTREACHED */
645
		default:
646
			quitenv(NULL);
647
			internal_errorf(1, "CFUNC %d", i);
648
		}
649
1189452
		break;
650
1189452
	    }
651
652
	case CEXEC:		/* executable command */
653
	case CTALIAS:		/* tracked alias */
654
1043867
		if (!(tp->flag&ISSET)) {
655
			/* errno_ will be set if the named command was found
656
			 * but could not be executed (permissions, no execute
657
			 * bit, directory, etc).  Print out a (hopefully)
658
			 * useful error message and set the exit status to 126.
659
			 */
660
2802
			if (tp->u2.errno_) {
661
1
				warningf(true, "%s: cannot execute - %s", cp,
662
1
				    strerror(tp->u2.errno_));
663
1
				rv = 126;	/* POSIX */
664
1
			} else {
665
2801
				warningf(true, "%s: not found", cp);
666
2801
				rv = 127;
667
			}
668
			break;
669
		}
670
671
1041065
		if (!Flag(FSH)) {
672
			/* set $_ to program's full path */
673
			/* setstr() can't fail here */
674
72478
			setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0),
675
36239
			    tp->val.s, KSH_RETURN_ERROR);
676
36239
		}
677
678
1041065
		if (flags&XEXEC) {
679
			j_exit();
680
			if (!(flags&XBGND) || Flag(FMONITOR)) {
681
				setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
682
				setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
683
			}
684
		}
685
686
		/* to fork we set up a TEXEC node and call execute */
687
1041065
		texec.type = TEXEC;
688
1041065
		texec.left = t;	/* for tprint */
689
1041065
		texec.str = tp->val.s;
690
1041065
		texec.args = ap;
691
1041065
		rv = exchild(&texec, flags, xerrok, -1);
692
1041065
		break;
693
	}
694
  Leave:
695
17798307
	if (flags & XEXEC) {
696
		exstat = rv;
697
		unwind(LLEAVE);
698
	}
699
17728540
	return rv;
700
17728540
}
701
702
static void
703
scriptexec(struct op *tp, char **ap)
704
{
705
	char *shell;
706
707
	shell = str_val(global("EXECSHELL"));
708
	if (shell && *shell)
709
		shell = search(shell, path, X_OK, NULL);
710
	if (!shell || !*shell)
711
		shell = _PATH_BSHELL;
712
713
	*tp->args-- = tp->str;
714
	*tp->args = shell;
715
716
	execve(tp->args[0], tp->args, ap);
717
718
	/* report both the program that was run and the bogus shell */
719
	errorf("%s: %s: %s", tp->str, shell, strerror(errno));
720
}
721
722
int
723
shcomexec(char **wp)
724
{
725
	struct tbl *tp;
726
727
3054230
	tp = ktsearch(&builtins, *wp, hash(*wp));
728
1527115
	if (tp == NULL)
729
		internal_errorf(1, "shcomexec: %s", *wp);
730
1527115
	return call_builtin(tp, wp);
731
}
732
733
/*
734
 * Search function tables for a function.  If create set, a table entry
735
 * is created if none is found.
736
 */
737
struct tbl *
738
findfunc(const char *name, unsigned int h, int create)
739
{
740
	struct block *l;
741
	struct tbl *tp = NULL;
742
743
67913838
	for (l = genv->loc; l; l = l->next) {
744
20927202
		tp = ktsearch(&l->funs, name, h);
745
20927202
		if (tp)
746
			break;
747
19701073
		if (!l->next && create) {
748
82945
			tp = ktenter(&l->funs, name, h);
749
82945
			tp->flag = DEFINED;
750
82945
			tp->type = CFUNC;
751
82945
			tp->val.t = NULL;
752
82945
			break;
753
		}
754
	}
755
9559194
	return tp;
756
}
757
758
/*
759
 * define function.  Returns 1 if function is being undefined (t == 0) and
760
 * function did not exist, returns 0 otherwise.
761
 */
762
int
763
define(const char *name, struct op *t)
764
{
765
	struct tbl *tp;
766
	int was_set = 0;
767
768
166054
	while (1) {
769
83027
		tp = findfunc(name, hash(name), true);
770
771
83027
		if (tp->flag & ISSET)
772
82
			was_set = 1;
773
		/* If this function is currently being executed, we zap this
774
		 * table entry so findfunc() won't see it
775
		 */
776
83027
		if (tp->flag & FINUSE) {
777
			tp->name[0] = '\0';
778
			tp->flag &= ~DEFINED; /* ensure it won't be found */
779
			tp->flag |= FDELETE;
780
		} else
781
			break;
782
	}
783
784
83027
	if (tp->flag & ALLOC) {
785
82
		tp->flag &= ~(ISSET|ALLOC);
786
82
		tfree(tp->val.t, tp->areap);
787
82
	}
788
789
83027
	if (t == NULL) {		/* undefine */
790
25
		ktdelete(tp);
791
25
		return was_set ? 0 : 1;
792
	}
793
794
83002
	tp->val.t = tcopy(t->left, tp->areap);
795
83002
	tp->flag |= (ISSET|ALLOC);
796
83002
	if (t->u.ksh_func)
797
150
		tp->flag |= FKSH;
798
799
83002
	return 0;
800
83027
}
801
802
/*
803
 * add builtin
804
 */
805
void
806
builtin(const char *name, int (*func) (char **))
807
{
808
	struct tbl *tp;
809
	int flag;
810
811
	/* see if any flags should be set for this builtin */
812
28745640
	for (flag = 0; ; name++) {
813
19599300
		if (*name == '=')	/* command does variable assignment */
814
3919860
			flag |= KEEPASN;
815
15679440
		else if (*name == '*')	/* POSIX special builtin */
816
3266550
			flag |= SPEC_BI;
817
12412890
		else if (*name == '+')	/* POSIX regular builtin */
818
3266550
			flag |= REG_BI;
819
		else
820
			break;
821
	}
822
823
9146340
	tp = ktenter(&builtins, name, hash(name));
824
9146340
	tp->flag = DEFINED | flag;
825
9146340
	tp->type = CSHELL;
826
9146340
	tp->val.f = func;
827
9146340
}
828
829
/*
830
 * find command
831
 * either function, hashed command, or built-in (in that order)
832
 */
833
struct tbl *
834
findcom(const char *name, int flags)
835
{
836
	static struct tbl temp;
837
24006080
	unsigned int h = hash(name);
838
	struct tbl *tp = NULL, *tbi;
839
12003040
	int insert = Flag(FTRACKALL);	/* insert if not found */
840
	char *fpath;			/* for function autoloading */
841
	char *npath;
842
843
12003040
	if (strchr(name, '/') != NULL) {
844
		insert = 0;
845
		/* prevent FPATH search below */
846
330085
		flags &= ~FC_FUNC;
847
330085
		goto Search;
848
	}
849
35018565
	tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
850
	/* POSIX says special builtins first, then functions, then
851
	 * POSIX regular builtins, then search path...
852
	 */
853

20361255
	if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
854
2196488
		tp = tbi;
855

21149422
	if (!tp && (flags & FC_FUNC)) {
856
9476167
		tp = findfunc(name, h, false);
857

10702214
		if (tp && !(tp->flag & ISSET)) {
858
			if ((fpath = str_val(global("FPATH"))) == null) {
859
				tp->u.fpath = NULL;
860
				tp->u2.errno_ = 0;
861
			} else
862
				tp->u.fpath = search(name, fpath, R_OK,
863
				    &tp->u2.errno_);
864
		}
865
	}
866

26415091
	if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
867
183893
		tp = tbi;
868
	/* todo: posix says non-special/non-regular builtins must
869
	 * be triggered by some user-controllable means like a
870
	 * special directory in PATH.  Requires modifications to
871
	 * the search() function.  Tracked aliases should be
872
	 * modified to allow tracking of builtin commands.
873
	 * This should be under control of the FPOSIX flag.
874
	 * If this is changed, also change c_whence...
875
	 */
876

19739482
	if (!tp && (flags & FC_UNREGBI) && tbi)
877
6307823
		tp = tbi;
878

14311008
	if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
879
879299
		tp = ktsearch(&taliases, name, h);
880

2449502
		if (tp && (tp->flag & ISSET) && access(tp->val.s, X_OK) != 0) {
881
			if (tp->flag & ALLOC) {
882
				tp->flag &= ~ALLOC;
883
				afree(tp->val.s, APERM);
884
			}
885
			tp->flag &= ~ISSET;
886
		}
887
	}
888
889
  Search:
890


24919664
	if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) &&
891
1346515
	    (flags & FC_PATH)) {
892
302180
		if (!tp) {
893

262605
			if (insert && !(flags & FC_DEFPATH)) {
894
46030
				tp = ktenter(&taliases, name, h);
895
				tp->type = CTALIAS;
896
46030
			} else {
897
				tp = &temp;
898
				tp->type = CEXEC;
899
			}
900
216525
			tp->flag = DEFINED;	/* make ~ISSET */
901
216525
		}
902
604360
		npath = search(name, flags & FC_DEFPATH ? def_path : path,
903
302180
		    X_OK, &tp->u2.errno_);
904
302180
		if (npath) {
905
299042
			if (tp == &temp) {
906
167708
				tp->val.s = npath;
907
167708
			} else {
908
131334
				tp->val.s = str_save(npath, APERM);
909
131334
				if (npath != name)
910
131334
					afree(npath, ATEMP);
911
			}
912
299042
			tp->flag |= ISSET|ALLOC;
913

302183
		} else if ((flags & FC_FUNC) &&
914
2699
		    (fpath = str_val(global("FPATH"))) != null &&
915
3
		    (npath = search(name, fpath, R_OK,
916
3
		    &tp->u2.errno_)) != NULL) {
917
			/* An undocumented feature of at&t ksh is that it
918
			 * searches FPATH if a command is not found, even
919
			 * if the command hasn't been set up as an autoloaded
920
			 * function (ie, no typeset -uf).
921
			 */
922
			tp = &temp;
923
			tp->type = CFUNC;
924
			tp->flag = DEFINED; /* make ~ISSET */
925
			tp->u.fpath = npath;
926
		}
927
	}
928
12003040
	return tp;
929
}
930
931
/*
932
 * flush executable commands with relative paths
933
 */
934
void
935
flushcom(int all)	/* just relative or all */
936
{
937
	struct tbl *tp;
938
964112
	struct tstate ts;
939
940
1801759
	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
941

838844
		if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
942
151
			if (tp->flag&ALLOC) {
943
151
				tp->flag &= ~(ALLOC|ISSET);
944
151
				afree(tp->val.s, APERM);
945
151
			}
946
151
			tp->flag &= ~ISSET;
947
151
		}
948
482056
}
949
950
/* Check if path is something we want to find.  Returns -1 for failure. */
951
int
952
search_access(const char *path, int mode,
953
    int *errnop)	/* set if candidate found, but not suitable */
954
{
955
	int ret, err = 0;
956
1280716
	struct stat statb;
957
958
640358
	if (stat(path, &statb) < 0)
959
335039
		return -1;
960
305319
	ret = access(path, mode);
961
305319
	if (ret < 0)
962
		err = errno; /* File exists, but we can't access it */
963

903478
	else if (mode == X_OK && (!S_ISREG(statb.st_mode) ||
964
299079
	    !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) {
965
	    /* This 'cause access() says root can execute everything */
966
		ret = -1;
967
1
		err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
968
1
	}
969

305320
	if (err && errnop && !*errnop)
970
1
		*errnop = err;
971
305319
	return ret;
972
640358
}
973
974
/*
975
 * search for command with PATH
976
 */
977
char *
978
search(const char *name, const char *path,
979
    int mode,		/* R_OK or X_OK */
980
    int *errnop)	/* set if candidate found, but not suitable */
981
{
982
	const char *sp, *p;
983
	char *xp;
984
616944
	XString xs;
985
	int namelen;
986
987
308472
	if (errnop)
988
308472
		*errnop = 0;
989
308472
	if (strchr(name, '/')) {
990
171394
		if (search_access(name, mode, errnop) == 0)
991
171105
			return (char *) name;
992
289
		return NULL;
993
	}
994
995
137078
	namelen = strlen(name) + 1;
996
137078
	Xinit(xs, xp, 128, ATEMP);
997
998
	sp = path;
999
943658
	while (sp != NULL) {
1000
		xp = Xstring(xs, xp);
1001
468927
		if (!(p = strchr(sp, ':')))
1002
5746
			p = sp + strlen(sp);
1003
468927
		if (p != sp) {
1004
468927
			XcheckN(xs, xp, p - sp);
1005
468927
			memcpy(xp, sp, p - sp);
1006
468927
			xp += p - sp;
1007
468927
			*xp++ = '/';
1008
468927
		}
1009
		sp = p;
1010
468927
		XcheckN(xs, xp, namelen);
1011
468927
		memcpy(xp, name, namelen);
1012
468927
		if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1013
134176
			return Xclose(xs, xp + namelen);
1014
334751
		if (*sp++ == '\0')
1015
			sp = NULL;
1016
	}
1017
2902
	Xfree(xs, xp);
1018
2902
	return NULL;
1019
308472
}
1020
1021
static int
1022
call_builtin(struct tbl *tp, char **wp)
1023
{
1024
	int rv;
1025
1026
20429988
	builtin_argv0 = wp[0];
1027
10214994
	builtin_flag = tp->flag;
1028
10214994
	shf_reopen(1, SHF_WR, shl_stdout);
1029
10214994
	shl_stdout_ok = 1;
1030
10214994
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
1031
10214994
	rv = (*tp->val.f)(wp);
1032
10214994
	shf_flush(shl_stdout);
1033
10214994
	shl_stdout_ok = 0;
1034
10214994
	builtin_flag = 0;
1035
10214994
	builtin_argv0 = NULL;
1036
10214994
	return rv;
1037
}
1038
1039
/*
1040
 * set up redirection, saving old fd's in e->savefd
1041
 */
1042
static int
1043
iosetup(struct ioword *iop, struct tbl *tp)
1044
{
1045
	int u = -1;
1046
3700258
	char *cp = iop->name;
1047
1850129
	int iotype = iop->flag & IOTYPE;
1048
	int do_open = 1, do_close = 0, flags = 0;
1049
1850129
	struct ioword iotmp;
1050
1850129
	struct stat statb;
1051
1052
1850129
	if (iotype != IOHERE)
1053
1646912
		cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
1054
1055
	/* Used for tracing and error messages to print expanded cp */
1056
1850129
	iotmp = *iop;
1057
1850129
	iotmp.name = (iotype == IOHERE) ? NULL : cp;
1058
1850129
	iotmp.flag |= IONAMEXP;
1059
1060
1850129
	if (Flag(FXTRACE))
1061
278
		shellf("%s%s\n",
1062
278
		    PS4_SUBSTITUTE(str_val(global("PS4"))),
1063
278
		    snptreef(NULL, 32, "%R", &iotmp));
1064
1065

3699797
	switch (iotype) {
1066
	case IOREAD:
1067
		flags = O_RDONLY;
1068
33095
		break;
1069
1070
	case IOCAT:
1071
		flags = O_WRONLY | O_APPEND | O_CREAT;
1072
251816
		break;
1073
1074
	case IOWRITE:
1075
		flags = O_WRONLY | O_CREAT | O_TRUNC;
1076
		/* The stat() is here to allow redirections to
1077
		 * things like /dev/null without error.
1078
		 */
1079

403974
		if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
1080
		    (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
1081
			flags |= O_EXCL;
1082
		break;
1083
1084
	case IORDWR:
1085
		flags = O_RDWR | O_CREAT;
1086
		break;
1087
1088
	case IOHERE:
1089
		do_open = 0;
1090
		/* herein() returns -2 if error has been printed */
1091
203217
		u = herein(iop->heredoc, iop->flag & IOEVAL);
1092
		/* cp may have wrong name */
1093
203217
		break;
1094
1095
	case IODUP:
1096
	    {
1097
958027
		const char *emsg;
1098
1099
		do_open = 0;
1100

958027
		if (*cp == '-' && !cp[1]) {
1101
			u = 1009;	 /* prevent error return below */
1102
			do_close = 1;
1103
1916054
		} else if ((u = check_fd(cp,
1104
958027
		    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
1105
958027
		    &emsg)) < 0) {
1106
			warningf(true, "%s: %s",
1107
			    snptreef(NULL, 32, "%R", &iotmp), emsg);
1108
			return -1;
1109
		}
1110
958027
		if (u == iop->unit)
1111
18
			return 0;		/* "dup from" == "dup to" */
1112
958009
		break;
1113
958027
	    }
1114
	}
1115
1116
1849668
	if (do_open) {
1117

688885
		if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
1118
			warningf(true, "%s: restricted", cp);
1119
			return -1;
1120
		}
1121
688885
		u = open(cp, flags, 0666);
1122
688885
	}
1123
1849668
	if (u < 0) {
1124
		/* herein() may already have printed message */
1125
		if (u == -1)
1126
			warningf(true, "cannot %s %s: %s",
1127
			    iotype == IODUP ? "dup" :
1128
			    (iotype == IOREAD || iotype == IOHERE) ?
1129
			    "open" : "create", cp, strerror(errno));
1130
		return -1;
1131
	}
1132
	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
1133
1849668
	if (genv->savefd[iop->unit] == 0) {
1134
		/* If these are the same, it means unit was previously closed */
1135
1849643
		if (u == iop->unit)
1136
6
			genv->savefd[iop->unit] = -1;
1137
		else
1138
			/* c_exec() assumes e->savefd[fd] set for any
1139
			 * redirections.  Ask savefd() not to close iop->unit;
1140
			 * this allows error messages to be seen if iop->unit
1141
			 * is 2; also means we can't lose the fd (eg, both
1142
			 * dup2 below and dup2 in restfd() failing).
1143
			 */
1144
1849637
			genv->savefd[iop->unit] = savefd(iop->unit);
1145
1849643
	}
1146
1147
1849668
	if (do_close)
1148
		close(iop->unit);
1149
1849668
	else if (u != iop->unit) {
1150
1849662
		if (ksh_dup2(u, iop->unit, true) < 0) {
1151
			warningf(true,
1152
			    "could not finish (dup) redirection %s: %s",
1153
			    snptreef(NULL, 32, "%R", &iotmp),
1154
			    strerror(errno));
1155
			if (iotype != IODUP)
1156
				close(u);
1157
			return -1;
1158
		}
1159
1849662
		if (iotype != IODUP)
1160
891653
			close(u);
1161
		/* Touching any co-process fd in an empty exec
1162
		 * causes the shell to close its copies
1163
		 */
1164

2405158
		else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
1165
72773
			if (iop->flag & IORDUP)	/* possible exec <&p */
1166
1853
				coproc_read_close(u);
1167
			else			/* possible exec >&p */
1168
70920
				coproc_write_close(u);
1169
		}
1170
	}
1171
1849668
	if (u == 2) /* Clear any write errors */
1172
2829
		shf_reopen(2, SHF_WR, shl_out);
1173
1849668
	return 0;
1174
1849686
}
1175
1176
/*
1177
 * open here document temp file.
1178
 * if unquoted here, expand here temp file into second temp file.
1179
 */
1180
static int
1181
herein(const char *content, int sub)
1182
{
1183
406434
	volatile int fd = -1;
1184
203217
	struct source *s, *volatile osource;
1185
203217
	struct shf *volatile shf;
1186
	struct temp *h;
1187
	int i;
1188
1189
	/* ksh -c 'cat << EOF' can cause this... */
1190
203217
	if (content == NULL) {
1191
		warningf(true, "here document missing");
1192
		return -2; /* special to iosetup(): don't print error */
1193
	}
1194
1195
	/* Create temp file to hold content (done before newenv so temp
1196
	 * doesn't get removed too soon).
1197
	 */
1198
203217
	h = maketemp(ATEMP, TT_HEREDOC_EXP, &genv->temps);
1199

406434
	if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) {
1200
		warningf(true, "can't %s temporary file %s: %s",
1201
		    !shf ? "create" : "open",
1202
		    h->name, strerror(errno));
1203
		if (shf)
1204
			shf_close(shf);
1205
		return -2 /* special to iosetup(): don't print error */;
1206
	}
1207
1208
203368
	osource = source;
1209
203368
	newenv(E_ERRH);
1210
203368
	i = sigsetjmp(genv->jbuf, 0);
1211
203368
	if (i) {
1212
151
		source = osource;
1213
151
		quitenv(shf);
1214
151
		close(fd);
1215
151
		return -2; /* special to iosetup(): don't print error */
1216
	}
1217
203217
	if (sub) {
1218
		/* Do substitutions on the content of heredoc */
1219
195461
		s = pushs(SSTRING, ATEMP);
1220
195461
		s->start = s->str = content;
1221
195461
		source = s;
1222
195461
		if (yylex(ONEWORD|HEREDOC) != LWORD)
1223
			internal_errorf(1, "herein: yylex");
1224
195461
		source = osource;
1225
195461
		shf_puts(evalstr(yylval.cp, 0), shf);
1226
195461
	} else
1227
7756
		shf_puts(content, shf);
1228
1229
202774
	quitenv(NULL);
1230
1231
202774
	if (shf_close(shf) == EOF) {
1232
		close(fd);
1233
		warningf(true, "error writing %s: %s", h->name,
1234
		    strerror(errno));
1235
		return -2; /* special to iosetup(): don't print error */
1236
	}
1237
1238
202774
	return fd;
1239
202774
}
1240
1241
#ifdef EDIT
1242
/*
1243
 *	ksh special - the select command processing section
1244
 *	print the args in column form - assuming that we can
1245
 */
1246
static char *
1247
do_selectargs(char **ap, bool print_menu)
1248
{
1249
	static const char *const read_args[] = {
1250
		"read", "-r", "REPLY", NULL
1251
	};
1252
	const char *errstr;
1253
	char *s;
1254
	int i, argct;
1255
1256
	for (argct = 0; ap[argct]; argct++)
1257
		;
1258
	while (1) {
1259
		/* Menu is printed if
1260
		 *	- this is the first time around the select loop
1261
		 *	- the user enters a blank line
1262
		 *	- the REPLY parameter is empty
1263
		 */
1264
		if (print_menu || !*str_val(global("REPLY")))
1265
			pr_menu(ap);
1266
		shellf("%s", str_val(global("PS3")));
1267
		if (call_builtin(findcom("read", FC_BI), (char **) read_args))
1268
			return NULL;
1269
		s = str_val(global("REPLY"));
1270
		if (*s) {
1271
			i = strtonum(s, 1, argct, &errstr);
1272
			if (errstr)
1273
				return null;
1274
			return ap[i - 1];
1275
		}
1276
		print_menu = 1;
1277
	}
1278
}
1279
1280
struct select_menu_info {
1281
	char	*const *args;
1282
	int	arg_width;
1283
	int	num_width;
1284
};
1285
1286
static char *select_fmt_entry(void *arg, int i, char *buf, int buflen);
1287
1288
/* format a single select menu item */
1289
static char *
1290
select_fmt_entry(void *arg, int i, char *buf, int buflen)
1291
{
1292
	struct select_menu_info *smi = (struct select_menu_info *) arg;
1293
1294
	shf_snprintf(buf, buflen, "%*d) %s",
1295
	    smi->num_width, i + 1, smi->args[i]);
1296
	return buf;
1297
}
1298
1299
/*
1300
 *	print a select style menu
1301
 */
1302
int
1303
pr_menu(char *const *ap)
1304
{
1305
	struct select_menu_info smi;
1306
	char *const *pp;
1307
	int nwidth, dwidth;
1308
	int i, n;
1309
1310
	/* Width/column calculations were done once and saved, but this
1311
	 * means select can't be used recursively so we re-calculate each
1312
	 * time (could save in a structure that is returned, but its probably
1313
	 * not worth the bother).
1314
	 */
1315
1316
	/*
1317
	 * get dimensions of the list
1318
	 */
1319
	for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1320
		i = strlen(*pp);
1321
		nwidth = (i > nwidth) ? i : nwidth;
1322
	}
1323
	/*
1324
	 * we will print an index of the form
1325
	 *	%d)
1326
	 * in front of each entry
1327
	 * get the max width of this
1328
	 */
1329
	for (i = n, dwidth = 1; i >= 10; i /= 10)
1330
		dwidth++;
1331
1332
	smi.args = ap;
1333
	smi.arg_width = nwidth;
1334
	smi.num_width = dwidth;
1335
	print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
1336
	    dwidth + nwidth + 2, 1);
1337
1338
	return n;
1339
}
1340
1341
/* XXX: horrible kludge to fit within the framework */
1342
1343
static char *plain_fmt_entry(void *arg, int i, char *buf, int buflen);
1344
1345
static char *
1346
plain_fmt_entry(void *arg, int i, char *buf, int buflen)
1347
{
1348
904
	shf_snprintf(buf, buflen, "%s", ((char *const *)arg)[i]);
1349
452
	return buf;
1350
}
1351
1352
int
1353
pr_list(char *const *ap)
1354
{
1355
	char *const *pp;
1356
	int nwidth;
1357
	int i, n;
1358
1359
1096
	for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1360
452
		i = strlen(*pp);
1361
452
		nwidth = (i > nwidth) ? i : nwidth;
1362
	}
1363
64
	print_columns(shl_out, n, plain_fmt_entry, (void *) ap, nwidth + 1, 0);
1364
1365
64
	return n;
1366
}
1367
#endif /* EDIT */
1368
1369
/*
1370
 *	[[ ... ]] evaluation routines
1371
 */
1372
1373
extern const char *const dbtest_tokens[];
1374
extern const char db_close[];
1375
1376
/* Test if the current token is a whatever.  Accepts the current token if
1377
 * it is.  Returns 0 if it is not, non-zero if it is (in the case of
1378
 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
1379
 */
1380
static int
1381
dbteste_isa(Test_env *te, Test_meta meta)
1382
{
1383
	int ret = 0;
1384
	int uqword;
1385
	char *p;
1386
1387
3171656
	if (!*te->pos.wp)
1388
646536
		return meta == TM_END;
1389
1390
	/* unquoted word? */
1391
3063394
	for (p = *te->pos.wp; *p == CHAR; p += 2)
1392
		;
1393
939292
	uqword = *p == EOS;
1394
1395
939292
	if (meta == TM_UNOP || meta == TM_BINOP) {
1396
445536
		if (uqword) {
1397
231196
			char buf[8];	/* longer than the longest operator */
1398
231196
			char *q = buf;
1399
1386888
			for (p = *te->pos.wp;
1400
1155692
			    *p == CHAR && q < &buf[sizeof(buf) - 1]; p += 2)
1401
462248
				*q++ = p[1];
1402
231196
			*q = '\0';
1403
231196
			ret = (int) test_isop(te, meta, buf);
1404
231196
		}
1405
493756
	} else if (meta == TM_END)
1406
		ret = 0;
1407
	else
1408
987512
		ret = uqword &&
1409
65076
		    strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
1410
1411
	/* Accept the token? */
1412
939292
	if (ret)
1413
246879
		te->pos.wp++;
1414
1415
939292
	return ret;
1416
1585828
}
1417
1418
static const char *
1419
dbteste_getopnd(Test_env *te, Test_op op, int do_eval)
1420
{
1421
891072
	char *s = *te->pos.wp;
1422
1423
445536
	if (!s)
1424
		return NULL;
1425
1426
445536
	te->pos.wp++;
1427
1428
445536
	if (!do_eval)
1429
2
		return null;
1430
1431
445534
	if (op == TO_STEQL || op == TO_STNEQ)
1432
214339
		s = evalstr(s, DOTILDE | DOPAT);
1433
	else
1434
231195
		s = evalstr(s, DOTILDE);
1435
1436
445534
	return s;
1437
445536
}
1438
1439
static int
1440
dbteste_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
1441
    int do_eval)
1442
{
1443
462390
	return test_eval(te, op, opnd1, opnd2, do_eval);
1444
}
1445
1446
static void
1447
dbteste_error(Test_env *te, int offset, const char *msg)
1448
{
1449
	te->flags |= TEF_ERROR;
1450
	internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset);
1451
}