GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/exec.c Lines: 477 711 67.1 %
Date: 2017-11-13 Branches: 354 528 67.0 %

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
10761622
	int i, dummy = 0, save_xerrok = 0;
49
10761622
	volatile int rv = 0;
50
10761622
	int pv[2];
51
10761622
	char ** volatile ap;
52
	char *s, *cp;
53
	struct ioword **iowp;
54
	struct tbl *tp = NULL;
55
56
10761622
	if (t == NULL)
57
721022
		return 0;
58
59
	/* Caller doesn't care if XERROK should propagate. */
60
10040600
	if (xerrok == NULL)
61
7208042
		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

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

5769002
		if (Flag(FXTRACE) && ap[0]) {
94
22568
			shf_fprintf(shl_out, "%s",
95
22568
				PS4_SUBSTITUTE(str_val(global("PS4"))));
96
141232
			for (i = 0; ap[i]; i++)
97
96096
				shf_fprintf(shl_out, "%s%s", ap[i],
98
48048
				    ap[i + 1] ? " " : "\n");
99
22568
			shf_flush(shl_out);
100
22568
		}
101
5746434
		if (ap[0])
102
3069498
			tp = findcom(ap[0], FC_BI|FC_FUNC);
103
	}
104
9548525
	flags &= ~XTIME;
105
106

27492757
	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
107
1078167
		genv->savefd = areallocarray(NULL, NUFILE, sizeof(short), ATEMP);
108
		/* initialize to not redirected */
109
1078167
		memset(genv->savefd, 0, NUFILE * sizeof(short));
110
1078167
	}
111
112
	/* do redirection, to be restored in quitenv() */
113
9548525
	if (t->ioact != NULL)
114
383934
		for (iowp = t->ioact; *iowp != NULL; iowp++) {
115
117316
			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





18671622
	switch (t->type) {
129
	case TCOM:
130
5746428
		rv = comexec(t, tp, ap, flags, xerrok);
131
5746428
		break;
132
133
	case TPAREN:
134
1670
		rv = execute(t->left, flags|XFORK, xerrok);
135
1670
		break;
136
137
	case TPIPE:
138
1003516
		flags |= XFORK;
139
1003516
		flags &= ~XEXEC;
140
1003516
		genv->savefd[0] = savefd(0);
141
1003516
		genv->savefd[1] = savefd(1);
142
4795978
		while (t->type == TPIPE) {
143
1409192
			openpipe(pv);
144
1409192
			(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
1409192
			exchild(t->left, flags|XPIPEO|XCCLOSE, NULL, pv[0]);
151
1409192
			(void) ksh_dup2(pv[0], 0, false); /* stdin of next */
152
1409192
			closepipe(pv);
153
1409192
			flags |= XPIPEI;
154
1409192
			t = t->right;
155
		}
156
974012
		restfd(1, genv->savefd[1]); /* stdout of last */
157
974012
		genv->savefd[1] = 0; /* no need to re-restore this */
158
		/* Let exchild() close 0 in parent, after fork, before wait */
159
974012
		i = exchild(t, flags|XPCLOSE, xerrok, 0);
160

1948018
		if (!(flags&XBGND) && !(flags&XXCOM))
161
98750
			rv = i;
162
		break;
163
164
	case TLIST:
165
10097175
		while (t->type == TLIST) {
166
4236829
			execute(t->left, flags & XERROK, NULL);
167
4236829
			t = t->right;
168
		}
169
779930
		rv = execute(t, flags & XERROK, xerrok);
170
779930
		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
775
		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
237
775
		break;
238
239
	case TOR:
240
	case TAND:
241
444954
		rv = execute(t->left, XERROK, xerrok);
242
444954
		if ((rv == 0) == (t->type == TAND))
243
185584
			rv = execute(t->right, flags & XERROK, xerrok);
244
		else {
245
259370
			flags |= XERROK;
246
259370
			*xerrok = 1;
247
		}
248
		break;
249
250
	case TBANG:
251
643
		rv = !execute(t->right, XERROK, xerrok);
252
643
		flags |= XERROK;
253
643
		*xerrok = 1;
254
643
		break;
255
256
	case TDBRACKET:
257
	    {
258
13234
		Test_env te;
259
260
13234
		te.flags = TEF_DBRACKET;
261
13234
		te.pos.wp = t->args;
262
13234
		te.isa = dbteste_isa;
263
13234
		te.getopnd = dbteste_getopnd;
264
13234
		te.eval = dbteste_eval;
265
13234
		te.error = dbteste_error;
266
267
13234
		rv = test_parse(&te);
268
		break;
269
13234
	    }
270
271
	case TFOR:
272
	case TSELECT:
273
	    {
274
32190
		volatile bool is_first = true;
275
96564
		ap = (t->vars != NULL) ? eval(t->vars, DOBLANK|DOGLOB|DOTILDE) :
276
308
		    genv->loc->argv + 1;
277
32184
		genv->type = E_LOOP;
278
32368
		while (1) {
279
32758
			i = sigsetjmp(genv->jbuf, 0);
280
32758
			if (!i)
281
				break;
282
390
			if ((genv->flags&EF_BRKCONT_PASS) ||
283
366
			    (i != LBREAK && i != LCONTIN)) {
284
				quitenv(NULL);
285
				unwind(i);
286
308
			} else if (i == LBREAK) {
287
124
				rv = 0;
288
124
				goto Break;
289
			}
290
		}
291
32368
		rv = 0; /* in case of a continue */
292
32368
		if (t->type == TFOR) {
293
32368
			save_xerrok = *xerrok;
294
443657
			while (*ap != NULL) {
295
190405
				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
296
				/* undo xerrok in all iterations except the
297
				 * last */
298
190405
				*xerrok = save_xerrok;
299
190405
				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
229490
	    }
314
		break;
315
316
	case TWHILE:
317
	case TUNTIL:
318
61475
		genv->type = E_LOOP;
319
62601
		while (1) {
320
63763
			i = sigsetjmp(genv->jbuf, 0);
321
63763
			if (!i)
322
				break;
323
1162
			if ((genv->flags&EF_BRKCONT_PASS) ||
324
1162
			    (i != LBREAK && i != LCONTIN)) {
325
				quitenv(NULL);
326
				unwind(i);
327
1132
			} else if (i == LBREAK) {
328
6
				rv = 0;
329
6
				goto Break;
330
			}
331
		}
332
62601
		rv = 0; /* in case of a continue */
333
327694
		while ((execute(t->left, XERROK, NULL) == 0) == (t->type == TWHILE))
334
102574
			rv = execute(t->right, flags & XERROK, xerrok);
335
		break;
336
337
	case TIF:
338
	case TELIF:
339
882844
		if (t->right == NULL)
340
			break;	/* should be error */
341
2635544
		rv = execute(t->left, XERROK, NULL) == 0 ?
342
141750
		    execute(t->right->left, flags & XERROK, xerrok) :
343
740821
		    execute(t->right->right, flags & XERROK, xerrok);
344
870402
		break;
345
346
	case TCASE:
347
15455
		cp = evalstr(t->str, DOTILDE);
348

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

50242
				if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
351
25121
				    gmatch(cp, s, false))
352
					goto Found;
353
			}
354
		}
355
		break;
356
	  Found:
357
14898
		rv = execute(t->left, flags & XERROK, xerrok);
358
14898
		break;
359
360
	case TBRACE:
361
474009
		rv = execute(t->left, flags & XERROK, xerrok);
362
474009
		break;
363
364
	case TFUNCT:
365
26168
		rv = define(t->str, t);
366
26168
		break;
367
368
	case TTIME:
369
		/* Clear XEXEC so nested execute() call doesn't exit
370
		 * (allows "ls -l | time grep foo").
371
		 */
372
1358
		rv = timex(t, flags & ~XEXEC, xerrok);
373
1358
		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
9222609
	exstat = rv;
388
389
9222609
	quitenv(NULL);		/* restores IO */
390
9222609
	if ((flags&XEXEC))
391
		unwind(LEXIT);	/* exit child */
392

10542633
	if (rv != 0 && !(flags & XERROK) && !*xerrok) {
393
11121
		trapsig(SIGERR_);
394
11121
		if (Flag(FERREXIT))
395
			unwind(LERROR);
396
	}
397
9219657
	return rv;
398
10424867
}
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
5746428
	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

5774289
	if (!Flag(FSH) && Flag(FTALKING) && *(lastp = ap)) {
424
4832
		while (*++lastp)
425
			;
426
		/* setstr() can't fail here */
427
860
		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
428
		    KSH_RETURN_ERROR);
429
860
	}
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

14425889
	while (tp && tp->type == CSHELL) {
445
		fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
446
2459025
		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
2459025
		} else if (tp->val.f == c_exec) {
456
36388
			if (ap[1] == NULL)
457
				break;
458
6
			ap++;
459
6
			flags |= XEXEC;
460
2422643
		} 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
144
			ksh_getopt_reset(&builtin_opt, 0);
467
432
			while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
468
				saw_p = 1;
469
144
			if (optc != EOF)
470
144
				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
6
		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
495
	}
496


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


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

2675183
		if (bourne_function_call && !(type_flags & EXPORT))
524
12
			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
525
	}
526
527
5735838
	if ((cp = *ap) == NULL) {
528
2666352
		rv = subst_exstat;
529
2666352
		goto Leave;
530
3069486
	} else if (!tp) {
531

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

8140172
	switch (tp->type) {
540
	case CSHELL:			/* shell built-in */
541
2459019
		rv = call_builtin(tp, ap);
542
2459019
		break;
543
544
	case CFUNC:			/* function call */
545
	    {
546
473996
		volatile int old_xflag, old_inuse;
547
473996
		const char *volatile old_kshname;
548
549
473996
		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
473996
		old_kshname = kshname;
589
473996
		if (tp->flag & FKSH)
590
2440
			kshname = ap[0];
591
		else
592
471556
			ap[0] = (char *) kshname;
593
473996
		genv->loc->argv = ap;
594
5128030
		for (i = 0; *ap++ != NULL; i++)
595
			;
596
473996
		genv->loc->argc = i - 1;
597
		/* ksh-style functions handle getopts sanely,
598
		 * bourne/posix functions are insane...
599
		 */
600
473996
		if (tp->flag & FKSH) {
601
2440
			genv->loc->flags |= BF_DOGETOPTS;
602
2440
			genv->loc->getopts_state = user_opt;
603
2440
			getopts_reset(1);
604
2440
		}
605
606
518310
		old_xflag = Flag(FXTRACE);
607
518310
		Flag(FXTRACE) = tp->flag & TRACE ? true : false;
608
609
518310
		old_inuse = tp->flag & FINUSE;
610
518310
		tp->flag |= FINUSE;
611
612
518310
		genv->type = E_FUNC;
613
518310
		i = sigsetjmp(genv->jbuf, 0);
614
518310
		if (i == 0) {
615
			/* seems odd to pass XERROK here, but at&t ksh does */
616
473996
			exstat = execute(tp->val.t, flags & XERROK, xerrok);
617
			i = LRETURN;
618
473996
		}
619
458027
		kshname = old_kshname;
620
458027
		Flag(FXTRACE) = old_xflag;
621
458027
		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
458027
		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

458027
		switch (i) {
634
		case LRETURN:
635
		case LERROR:
636
457761
			rv = exstat;
637
457761
			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
457761
		break;
650
457761
	    }
651
652
	case CEXEC:		/* executable command */
653
	case CTALIAS:		/* tracked alias */
654
136471
		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
63
			if (tp->u2.errno_) {
661
				warningf(true, "%s: cannot execute - %s", cp,
662
				    strerror(tp->u2.errno_));
663
				rv = 126;	/* POSIX */
664
			} else {
665
63
				warningf(true, "%s: not found", cp);
666
63
				rv = 127;
667
			}
668
			break;
669
		}
670
671
136408
		if (!Flag(FSH)) {
672
			/* set $_ to program's full path */
673
			/* setstr() can't fail here */
674
962
			setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0),
675
481
			    tp->val.s, KSH_RETURN_ERROR);
676
481
		}
677
678
136408
		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
136408
		texec.type = TEXEC;
688
136408
		texec.left = t;	/* for tprint */
689
136408
		texec.str = tp->val.s;
690
136408
		texec.args = ap;
691
136408
		rv = exchild(&texec, flags, xerrok, -1);
692
136408
		break;
693
	}
694
  Leave:
695
5673241
	if (flags & XEXEC) {
696
		exstat = rv;
697
		unwind(LLEAVE);
698
	}
699
5641204
	return rv;
700
5641204
}
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
1467990
	tp = ktsearch(&builtins, *wp, hash(*wp));
728
733995
	if (tp == NULL)
729
		internal_errorf(1, "shcomexec: %s", *wp);
730
733995
	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
19236833
	for (l = genv->loc; l; l = l->next) {
744
6121360
		tp = ktsearch(&l->funs, name, h);
745
6121360
		if (tp)
746
			break;
747
5647302
		if (!l->next && create) {
748
26156
			tp = ktenter(&l->funs, name, h);
749
26156
			tp->flag = DEFINED;
750
26156
			tp->type = CFUNC;
751
26156
			tp->val.t = NULL;
752
26156
			break;
753
		}
754
	}
755
2664847
	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
52348
	while (1) {
769
26174
		tp = findfunc(name, hash(name), true);
770
771
26174
		if (tp->flag & ISSET)
772
18
			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
26174
		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
26174
	if (tp->flag & ALLOC) {
785
18
		tp->flag &= ~(ISSET|ALLOC);
786
18
		tfree(tp->val.t, tp->areap);
787
18
	}
788
789
26174
	if (t == NULL) {		/* undefine */
790
6
		ktdelete(tp);
791
6
		return was_set ? 0 : 1;
792
	}
793
794
26168
	tp->val.t = tcopy(t->left, tp->areap);
795
26168
	tp->flag |= (ISSET|ALLOC);
796
26168
	if (t->u.ksh_func)
797
60
		tp->flag |= FKSH;
798
799
26168
	return 0;
800
26174
}
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
13828716
	for (flag = 0; ; name++) {
813
9428670
		if (*name == '=')	/* command does variable assignment */
814
1885734
			flag |= KEEPASN;
815
7542936
		else if (*name == '*')	/* POSIX special builtin */
816
1571445
			flag |= SPEC_BI;
817
5971491
		else if (*name == '+')	/* POSIX regular builtin */
818
1571445
			flag |= REG_BI;
819
		else
820
			break;
821
	}
822
823
4400046
	tp = ktenter(&builtins, name, hash(name));
824
4400046
	tp->flag = DEFINED | flag;
825
4400046
	tp->type = CSHELL;
826
4400046
	tp->val.f = func;
827
4400046
}
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
6412468
	unsigned int h = hash(name);
838
	struct tbl *tp = NULL, *tbi;
839
3206234
	int insert = Flag(FTRACKALL);	/* insert if not found */
840
	char *fpath;			/* for function autoloading */
841
	char *npath;
842
843
3206234
	if (strchr(name, '/') != NULL) {
844
		insert = 0;
845
		/* prevent FPATH search below */
846
140962
		flags &= ~FC_FUNC;
847
140962
		goto Search;
848
	}
849
9195744
	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

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

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

3112713
		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

7262547
	if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
867
30101
		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

5199876
	if (!tp && (flags & FC_UNREGBI) && tbi)
877
2002469
		tp = tbi;
878

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

127906
		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


6498292
	if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) &&
891
260505
	    (flags & FC_PATH)) {
892
124022
		if (!tp) {
893

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

124022
		} else if ((flags & FC_FUNC) &&
914
55
		    (fpath = str_val(global("FPATH"))) != null &&
915
		    (npath = search(name, fpath, R_OK,
916
		    &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
3206234
	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
465698
	struct tstate ts;
939
940
1305528
	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
941

420209
		if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
942
32
			if (tp->flag&ALLOC) {
943
32
				tp->flag &= ~(ALLOC|ISSET);
944
32
				afree(tp->val.s, APERM);
945
32
			}
946
32
			tp->flag &= ~ISSET;
947
32
		}
948
232849
}
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
545672
	struct stat statb;
957
958
272836
	if (stat(path, &statb) < 0)
959
147570
		return -1;
960
125266
	ret = access(path, mode);
961
125266
	if (ret < 0)
962
		err = errno; /* File exists, but we can't access it */
963

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

125266
	if (err && errnop && !*errnop)
970
		*errnop = err;
971
125266
	return ret;
972
272836
}
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
250840
	XString xs;
985
	int namelen;
986
987
125420
	if (errnop)
988
125420
		*errnop = 0;
989
125420
	if (strchr(name, '/')) {
990
71894
		if (search_access(name, mode, errnop) == 0)
991
71840
			return (char *) name;
992
54
		return NULL;
993
	}
994
995
53526
	namelen = strlen(name) + 1;
996
53526
	Xinit(xs, xp, 128, ATEMP);
997
998
	sp = path;
999
402084
	while (sp != NULL) {
1000
		xp = Xstring(xs, xp);
1001
200939
		if (!(p = strchr(sp, ':')))
1002
216
			p = sp + strlen(sp);
1003
200939
		if (p != sp) {
1004
200939
			XcheckN(xs, xp, p - sp);
1005
200939
			memcpy(xp, sp, p - sp);
1006
200939
			xp += p - sp;
1007
200939
			*xp++ = '/';
1008
200939
		}
1009
		sp = p;
1010
200939
		XcheckN(xs, xp, namelen);
1011
200939
		memcpy(xp, name, namelen);
1012
200939
		if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1013
53423
			return Xclose(xs, xp + namelen);
1014
147516
		if (*sp++ == '\0')
1015
			sp = NULL;
1016
	}
1017
103
	Xfree(xs, xp);
1018
103
	return NULL;
1019
125420
}
1020
1021
static int
1022
call_builtin(struct tbl *tp, char **wp)
1023
{
1024
	int rv;
1025
1026
6386028
	builtin_argv0 = wp[0];
1027
3193014
	builtin_flag = tp->flag;
1028
3193014
	shf_reopen(1, SHF_WR, shl_stdout);
1029
3193014
	shl_stdout_ok = 1;
1030
3193014
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
1031
3193014
	rv = (*tp->val.f)(wp);
1032
3193014
	shf_flush(shl_stdout);
1033
3193014
	shl_stdout_ok = 0;
1034
3193014
	builtin_flag = 0;
1035
3193014
	builtin_argv0 = NULL;
1036
3193014
	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
234644
	char *cp = iop->name;
1047
117322
	int iotype = iop->flag & IOTYPE;
1048
	int do_open = 1, do_close = 0, flags = 0;
1049
117322
	struct ioword iotmp;
1050
117322
	struct stat statb;
1051
1052
117322
	if (iotype != IOHERE)
1053
115244
		cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
1054
1055
	/* Used for tracing and error messages to print expanded cp */
1056
117322
	iotmp = *iop;
1057
117322
	iotmp.name = (iotype == IOHERE) ? NULL : cp;
1058
117322
	iotmp.flag |= IONAMEXP;
1059
1060
117322
	if (Flag(FXTRACE))
1061
		shellf("%s%s\n",
1062
		    PS4_SUBSTITUTE(str_val(global("PS4"))),
1063
		    snptreef(NULL, 32, "%R", &iotmp));
1064
1065

234630
	switch (iotype) {
1066
	case IOREAD:
1067
		flags = O_RDONLY;
1068
8554
		break;
1069
1070
	case IOCAT:
1071
		flags = O_WRONLY | O_APPEND | O_CREAT;
1072
51424
		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

14713
		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
2078
		u = herein(iop->heredoc, iop->flag & IOEVAL);
1092
		/* cp may have wrong name */
1093
2078
		break;
1094
1095
	case IODUP:
1096
	    {
1097
40553
		const char *emsg;
1098
1099
		do_open = 0;
1100

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

74691
		if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
1118
			warningf(true, "%s: restricted", cp);
1119
			return -1;
1120
		}
1121
74691
		u = open(cp, flags, 0666);
1122
74691
	}
1123
117308
	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
117308
	if (genv->savefd[iop->unit] == 0) {
1134
		/* If these are the same, it means unit was previously closed */
1135
117302
		if (u == iop->unit)
1136
1
			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
117301
			genv->savefd[iop->unit] = savefd(iop->unit);
1145
117302
	}
1146
1147
117308
	if (do_close)
1148
		close(iop->unit);
1149
117308
	else if (u != iop->unit) {
1150
117307
		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
117307
		if (iotype != IODUP)
1160
76762
			close(u);
1161
		/* Touching any co-process fd in an empty exec
1162
		 * causes the shell to close its copies
1163
		 */
1164

120443
		else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
1165
39298
			if (iop->flag & IORDUP)	/* possible exec <&p */
1166
				coproc_read_close(u);
1167
			else			/* possible exec >&p */
1168
39298
				coproc_write_close(u);
1169
		}
1170
	}
1171
117308
	if (u == 2) /* Clear any write errors */
1172
1456
		shf_reopen(2, SHF_WR, shl_out);
1173
117308
	return 0;
1174
117316
}
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
4156
	volatile int fd = -1;
1184
2078
	struct source *s, *volatile osource;
1185
2078
	struct shf *volatile shf;
1186
	struct temp *h;
1187
	int i;
1188
1189
	/* ksh -c 'cat << EOF' can cause this... */
1190
2078
	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
2078
	h = maketemp(ATEMP, TT_HEREDOC_EXP, &genv->temps);
1199

4156
	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
2084
	osource = source;
1209
2084
	newenv(E_ERRH);
1210
2084
	i = sigsetjmp(genv->jbuf, 0);
1211
2084
	if (i) {
1212
6
		source = osource;
1213
6
		quitenv(shf);
1214
6
		close(fd);
1215
6
		return -2; /* special to iosetup(): don't print error */
1216
	}
1217
2078
	if (sub) {
1218
		/* Do substitutions on the content of heredoc */
1219
1996
		s = pushs(SSTRING, ATEMP);
1220
1996
		s->start = s->str = content;
1221
1996
		source = s;
1222
1996
		if (yylex(ONEWORD|HEREDOC) != LWORD)
1223
			internal_errorf(1, "herein: yylex");
1224
1996
		source = osource;
1225
1996
		shf_puts(evalstr(yylval.cp, 0), shf);
1226
1996
	} else
1227
82
		shf_puts(content, shf);
1228
1229
2072
	quitenv(NULL);
1230
1231
2072
	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
2072
	return fd;
1239
2072
}
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
	shf_snprintf(buf, buflen, "%s", ((char *const *)arg)[i]);
1349
	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
	for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1360
		i = strlen(*pp);
1361
		nwidth = (i > nwidth) ? i : nwidth;
1362
	}
1363
	print_columns(shl_out, n, plain_fmt_entry, (void *) ap, nwidth + 1, 0);
1364
1365
	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
185080
	if (!*te->pos.wp)
1388
39702
		return meta == TM_END;
1389
1390
	/* unquoted word? */
1391
159396
	for (p = *te->pos.wp; *p == CHAR; p += 2)
1392
		;
1393
52838
	uqword = *p == EOS;
1394
1395
52838
	if (meta == TM_UNOP || meta == TM_BINOP) {
1396
26370
		if (uqword) {
1397
13234
			char buf[8];	/* longer than the longest operator */
1398
13234
			char *q = buf;
1399
79404
			for (p = *te->pos.wp;
1400
66170
			    *p == CHAR && q < &buf[sizeof(buf) - 1]; p += 2)
1401
26468
				*q++ = p[1];
1402
13234
			*q = '\0';
1403
13234
			ret = (int) test_isop(te, meta, buf);
1404
13234
		}
1405
26468
	} else if (meta == TM_END)
1406
		ret = 0;
1407
	else
1408
52936
		ret = uqword &&
1409
196
		    strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
1410
1411
	/* Accept the token? */
1412
52838
	if (ret)
1413
13234
		te->pos.wp++;
1414
1415
52838
	return ret;
1416
92540
}
1417
1418
static const char *
1419
dbteste_getopnd(Test_env *te, Test_op op, int do_eval)
1420
{
1421
52740
	char *s = *te->pos.wp;
1422
1423
26370
	if (!s)
1424
		return NULL;
1425
1426
26370
	te->pos.wp++;
1427
1428
26370
	if (!do_eval)
1429
		return null;
1430
1431
26370
	if (op == TO_STEQL || op == TO_STNEQ)
1432
13136
		s = evalstr(s, DOTILDE | DOPAT);
1433
	else
1434
13234
		s = evalstr(s, DOTILDE);
1435
1436
26370
	return s;
1437
26370
}
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
26468
	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
}