~ubuntu-branches/debian/sid/mksh/sid

« back to all changes in this revision

Viewing changes to .pc/debian-changes/exec.c

  • Committer: Package Import Robot
  • Author(s): Thorsten Glaser
  • Date: 2015-03-07 22:16:53 UTC
  • Revision ID: package-import@ubuntu.com-20150307221653-v1jz7r6cmocbjygj
Tags: 50d-5
* QA upload.
* Backport upstream fix:
  - [tg] SECURITY: make unset HISTFILE actually work
* Adjust shell version accordingly

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $       */
 
2
 
 
3
/*-
 
4
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
5
 *               2011, 2012, 2013, 2014
 
6
 *      Thorsten Glaser <tg@mirbsd.org>
 
7
 *
 
8
 * Provided that these terms and disclaimer and all copyright notices
 
9
 * are retained or reproduced in an accompanying document, permission
 
10
 * is granted to deal in this work without restriction, including un-
 
11
 * limited rights to use, publicly perform, distribute, sell, modify,
 
12
 * merge, give away, or sublicence.
 
13
 *
 
14
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
 
15
 * the utmost extent permitted by applicable law, neither express nor
 
16
 * implied; without malicious intent or gross negligence. In no event
 
17
 * may a licensor, author or contributor be held liable for indirect,
 
18
 * direct, other damage, loss, or other issues arising in any way out
 
19
 * of dealing in the work, even if advised of the possibility of such
 
20
 * damage or existence of a defect, except proven that it results out
 
21
 * of said person's immediate fault when using the work as intended.
 
22
 */
 
23
 
 
24
#include "sh.h"
 
25
 
 
26
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.133 2014/10/03 17:32:11 tg Exp $");
 
27
 
 
28
#ifndef MKSH_DEFAULT_EXECSHELL
 
29
#define MKSH_DEFAULT_EXECSHELL  "/bin/sh"
 
30
#endif
 
31
 
 
32
static int comexec(struct op *, struct tbl * volatile, const char **,
 
33
    int volatile, volatile int *);
 
34
static void scriptexec(struct op *, const char **) MKSH_A_NORETURN;
 
35
static int call_builtin(struct tbl *, const char **, const char *);
 
36
static int iosetup(struct ioword *, struct tbl *);
 
37
static int herein(struct ioword *, char **);
 
38
static const char *do_selectargs(const char **, bool);
 
39
static Test_op dbteste_isa(Test_env *, Test_meta);
 
40
static const char *dbteste_getopnd(Test_env *, Test_op, bool);
 
41
static void dbteste_error(Test_env *, int, const char *);
 
42
static int search_access(const char *, int);
 
43
/* XXX: horrible kludge to fit within the framework */
 
44
static char *plain_fmt_entry(char *, size_t, unsigned int, const void *);
 
45
static char *select_fmt_entry(char *, size_t, unsigned int, const void *);
 
46
 
 
47
/*
 
48
 * execute command tree
 
49
 */
 
50
int
 
51
execute(struct op * volatile t,
 
52
    /* if XEXEC don't fork */
 
53
    volatile int flags,
 
54
    volatile int * volatile xerrok)
 
55
{
 
56
        int i;
 
57
        volatile int rv = 0, dummy = 0;
 
58
        int pv[2];
 
59
        const char ** volatile ap = NULL;
 
60
        char ** volatile up;
 
61
        const char *s, *ccp;
 
62
        struct ioword **iowp;
 
63
        struct tbl *tp = NULL;
 
64
        char *cp;
 
65
 
 
66
        if (t == NULL)
 
67
                return (0);
 
68
 
 
69
        /* Caller doesn't care if XERROK should propagate. */
 
70
        if (xerrok == NULL)
 
71
                xerrok = &dummy;
 
72
 
 
73
        if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
 
74
                /* run in sub-process */
 
75
                return (exchild(t, flags & ~XTIME, xerrok, -1));
 
76
 
 
77
        newenv(E_EXEC);
 
78
        if (trap)
 
79
                runtraps(0);
 
80
 
 
81
        /* we want to run an executable, do some variance checks */
 
82
        if (t->type == TCOM) {
 
83
                /* check if this is 'var=<<EOF' */
 
84
                if (
 
85
                    /* we have zero arguments, i.e. no programme to run */
 
86
                    t->args[0] == NULL &&
 
87
                    /* we have exactly one variable assignment */
 
88
                    t->vars[0] != NULL && t->vars[1] == NULL &&
 
89
                    /* we have exactly one I/O redirection */
 
90
                    t->ioact != NULL && t->ioact[0] != NULL &&
 
91
                    t->ioact[1] == NULL &&
 
92
                    /* of type "here document" (or "here string") */
 
93
                    (t->ioact[0]->flag & IOTYPE) == IOHERE &&
 
94
                    /* the variable assignment begins with a valid varname */
 
95
                    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
 
96
                    /* and has no right-hand side (i.e. "varname=") */
 
97
                    ccp[0] == CHAR && ccp[1] == '=' && ccp[2] == EOS &&
 
98
                    /* plus we can have a here document content */
 
99
                    herein(t->ioact[0], &cp) == 0 && cp && *cp) {
 
100
                        char *sp = cp, *dp;
 
101
                        size_t n = ccp - t->vars[0] + 2, z;
 
102
 
 
103
                        /* drop redirection (will be garbage collected) */
 
104
                        t->ioact = NULL;
 
105
 
 
106
                        /* set variable to its expanded value */
 
107
                        z = strlen(cp) + 1;
 
108
                        if (notoktomul(z, 2) || notoktoadd(z * 2, n))
 
109
                                internal_errorf(Toomem, (size_t)-1);
 
110
                        dp = alloc(z * 2 + n, ATEMP);
 
111
                        memcpy(dp, t->vars[0], n);
 
112
                        t->vars[0] = dp;
 
113
                        dp += n;
 
114
                        while (*sp) {
 
115
                                *dp++ = QCHAR;
 
116
                                *dp++ = *sp++;
 
117
                        }
 
118
                        *dp = EOS;
 
119
                        /* free the expanded value */
 
120
                        afree(cp, APERM);
 
121
                }
 
122
 
 
123
                /*
 
124
                 * Clear subst_exstat before argument expansion. Used by
 
125
                 * null commands (see comexec() and c_eval()) and by c_set().
 
126
                 */
 
127
                subst_exstat = 0;
 
128
 
 
129
                /* for $LINENO */
 
130
                current_lineno = t->lineno;
 
131
 
 
132
                /*
 
133
                 * POSIX says expand command words first, then redirections,
 
134
                 * and assignments last..
 
135
                 */
 
136
                up = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
 
137
                if (flags & XTIME)
 
138
                        /* Allow option parsing (bizarre, but POSIX) */
 
139
                        timex_hook(t, &up);
 
140
                ap = (const char **)up;
 
141
                if (ap[0])
 
142
                        tp = findcom(ap[0], FC_BI|FC_FUNC);
 
143
        }
 
144
        flags &= ~XTIME;
 
145
 
 
146
        if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
 
147
                e->savefd = alloc2(NUFILE, sizeof(short), ATEMP);
 
148
                /* initialise to not redirected */
 
149
                memset(e->savefd, 0, NUFILE * sizeof(short));
 
150
        }
 
151
 
 
152
        /* mark for replacement later (unless TPIPE) */
 
153
        vp_pipest->flag |= INT_L;
 
154
 
 
155
        /* do redirection, to be restored in quitenv() */
 
156
        if (t->ioact != NULL)
 
157
                for (iowp = t->ioact; *iowp != NULL; iowp++) {
 
158
                        if (iosetup(*iowp, tp) < 0) {
 
159
                                exstat = rv = 1;
 
160
                                /*
 
161
                                 * Redirection failures for special commands
 
162
                                 * cause (non-interactive) shell to exit.
 
163
                                 */
 
164
                                if (tp && tp->type == CSHELL &&
 
165
                                    (tp->flag & SPEC_BI))
 
166
                                        errorfz();
 
167
                                /* Deal with FERREXIT, quitenv(), etc. */
 
168
                                goto Break;
 
169
                        }
 
170
                }
 
171
 
 
172
        switch (t->type) {
 
173
        case TCOM:
 
174
                rv = comexec(t, tp, (const char **)ap, flags, xerrok);
 
175
                break;
 
176
 
 
177
        case TPAREN:
 
178
                rv = execute(t->left, flags | XFORK, xerrok);
 
179
                break;
 
180
 
 
181
        case TPIPE:
 
182
                flags |= XFORK;
 
183
                flags &= ~XEXEC;
 
184
                e->savefd[0] = savefd(0);
 
185
                e->savefd[1] = savefd(1);
 
186
                while (t->type == TPIPE) {
 
187
                        openpipe(pv);
 
188
                        /* stdout of curr */
 
189
                        ksh_dup2(pv[1], 1, false);
 
190
                        /**
 
191
                         * Let exchild() close pv[0] in child
 
192
                         * (if this isn't done, commands like
 
193
                         *      (: ; cat /etc/termcap) | sleep 1
 
194
                         * will hang forever).
 
195
                         */
 
196
                        exchild(t->left, flags | XPIPEO | XCCLOSE,
 
197
                            NULL, pv[0]);
 
198
                        /* stdin of next */
 
199
                        ksh_dup2(pv[0], 0, false);
 
200
                        closepipe(pv);
 
201
                        flags |= XPIPEI;
 
202
                        t = t->right;
 
203
                }
 
204
                /* stdout of last */
 
205
                restfd(1, e->savefd[1]);
 
206
                /* no need to re-restore this */
 
207
                e->savefd[1] = 0;
 
208
                /* Let exchild() close 0 in parent, after fork, before wait */
 
209
                i = exchild(t, flags | XPCLOSE | XPIPEST, xerrok, 0);
 
210
                if (!(flags&XBGND) && !(flags&XXCOM))
 
211
                        rv = i;
 
212
                break;
 
213
 
 
214
        case TLIST:
 
215
                while (t->type == TLIST) {
 
216
                        execute(t->left, flags & XERROK, NULL);
 
217
                        t = t->right;
 
218
                }
 
219
                rv = execute(t, flags & XERROK, xerrok);
 
220
                break;
 
221
 
 
222
        case TCOPROC: {
 
223
#ifndef MKSH_NOPROSPECTOFWORK
 
224
                sigset_t omask;
 
225
 
 
226
                /*
 
227
                 * Block sigchild as we are using things changed in the
 
228
                 * signal handler
 
229
                 */
 
230
                sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
 
231
                e->type = E_ERRH;
 
232
                if ((i = kshsetjmp(e->jbuf))) {
 
233
                        sigprocmask(SIG_SETMASK, &omask, NULL);
 
234
                        quitenv(NULL);
 
235
                        unwind(i);
 
236
                        /* NOTREACHED */
 
237
                }
 
238
#endif
 
239
                /* Already have a (live) co-process? */
 
240
                if (coproc.job && coproc.write >= 0)
 
241
                        errorf("coprocess already exists");
 
242
 
 
243
                /* Can we re-use the existing co-process pipe? */
 
244
                coproc_cleanup(true);
 
245
 
 
246
                /* do this before opening pipes, in case these fail */
 
247
                e->savefd[0] = savefd(0);
 
248
                e->savefd[1] = savefd(1);
 
249
 
 
250
                openpipe(pv);
 
251
                if (pv[0] != 0) {
 
252
                        ksh_dup2(pv[0], 0, false);
 
253
                        close(pv[0]);
 
254
                }
 
255
                coproc.write = pv[1];
 
256
                coproc.job = NULL;
 
257
 
 
258
                if (coproc.readw >= 0)
 
259
                        ksh_dup2(coproc.readw, 1, false);
 
260
                else {
 
261
                        openpipe(pv);
 
262
                        coproc.read = pv[0];
 
263
                        ksh_dup2(pv[1], 1, false);
 
264
                        /* closed before first read */
 
265
                        coproc.readw = pv[1];
 
266
                        coproc.njobs = 0;
 
267
                        /* create new coprocess id */
 
268
                        ++coproc.id;
 
269
                }
 
270
#ifndef MKSH_NOPROSPECTOFWORK
 
271
                sigprocmask(SIG_SETMASK, &omask, NULL);
 
272
                /* no more need for error handler */
 
273
                e->type = E_EXEC;
 
274
#endif
 
275
 
 
276
                /*
 
277
                 * exchild() closes coproc.* in child after fork,
 
278
                 * will also increment coproc.njobs when the
 
279
                 * job is actually created.
 
280
                 */
 
281
                flags &= ~XEXEC;
 
282
                exchild(t->left, flags | XBGND | XFORK | XCOPROC | XCCLOSE,
 
283
                    NULL, coproc.readw);
 
284
                break;
 
285
        }
 
286
 
 
287
        case TASYNC:
 
288
                /*
 
289
                 * XXX non-optimal, I think - "(foo &)", forks for (),
 
290
                 * forks again for async... parent should optimise
 
291
                 * this to "foo &"...
 
292
                 */
 
293
                rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
 
294
                break;
 
295
 
 
296
        case TOR:
 
297
        case TAND:
 
298
                rv = execute(t->left, XERROK, xerrok);
 
299
                if ((rv == 0) == (t->type == TAND))
 
300
                        rv = execute(t->right, flags & XERROK, xerrok);
 
301
                else {
 
302
                        flags |= XERROK;
 
303
                        if (xerrok)
 
304
                                *xerrok = 1;
 
305
                }
 
306
                break;
 
307
 
 
308
        case TBANG:
 
309
                rv = !execute(t->right, XERROK, xerrok);
 
310
                flags |= XERROK;
 
311
                if (xerrok)
 
312
                        *xerrok = 1;
 
313
                break;
 
314
 
 
315
        case TDBRACKET: {
 
316
                Test_env te;
 
317
 
 
318
                te.flags = TEF_DBRACKET;
 
319
                te.pos.wp = t->args;
 
320
                te.isa = dbteste_isa;
 
321
                te.getopnd = dbteste_getopnd;
 
322
                te.eval = test_eval;
 
323
                te.error = dbteste_error;
 
324
 
 
325
                rv = test_parse(&te);
 
326
                break;
 
327
        }
 
328
 
 
329
        case TFOR:
 
330
        case TSELECT: {
 
331
                volatile bool is_first = true;
 
332
 
 
333
                ap = (t->vars == NULL) ? e->loc->argv + 1 :
 
334
                    (const char **)eval((const char **)t->vars,
 
335
                    DOBLANK | DOGLOB | DOTILDE);
 
336
                e->type = E_LOOP;
 
337
                while ((i = kshsetjmp(e->jbuf))) {
 
338
                        if ((e->flags&EF_BRKCONT_PASS) ||
 
339
                            (i != LBREAK && i != LCONTIN)) {
 
340
                                quitenv(NULL);
 
341
                                unwind(i);
 
342
                        } else if (i == LBREAK) {
 
343
                                rv = 0;
 
344
                                goto Break;
 
345
                        }
 
346
                }
 
347
                /* in case of a continue */
 
348
                rv = 0;
 
349
                if (t->type == TFOR) {
 
350
                        while (*ap != NULL) {
 
351
                                setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
 
352
                                rv = execute(t->left, flags & XERROK, xerrok);
 
353
                        }
 
354
                } else {
 
355
                        /* TSELECT */
 
356
                        for (;;) {
 
357
                                if (!(ccp = do_selectargs(ap, is_first))) {
 
358
                                        rv = 1;
 
359
                                        break;
 
360
                                }
 
361
                                is_first = false;
 
362
                                setstr(global(t->str), ccp, KSH_UNWIND_ERROR);
 
363
                                execute(t->left, flags & XERROK, xerrok);
 
364
                        }
 
365
                }
 
366
                break;
 
367
        }
 
368
 
 
369
        case TWHILE:
 
370
        case TUNTIL:
 
371
                e->type = E_LOOP;
 
372
                while ((i = kshsetjmp(e->jbuf))) {
 
373
                        if ((e->flags&EF_BRKCONT_PASS) ||
 
374
                            (i != LBREAK && i != LCONTIN)) {
 
375
                                quitenv(NULL);
 
376
                                unwind(i);
 
377
                        } else if (i == LBREAK) {
 
378
                                rv = 0;
 
379
                                goto Break;
 
380
                        }
 
381
                }
 
382
                /* in case of a continue */
 
383
                rv = 0;
 
384
                while ((execute(t->left, XERROK, NULL) == 0) ==
 
385
                    (t->type == TWHILE))
 
386
                        rv = execute(t->right, flags & XERROK, xerrok);
 
387
                break;
 
388
 
 
389
        case TIF:
 
390
        case TELIF:
 
391
                if (t->right == NULL)
 
392
                        /* should be error */
 
393
                        break;
 
394
                rv = execute(t->left, XERROK, NULL) == 0 ?
 
395
                    execute(t->right->left, flags & XERROK, xerrok) :
 
396
                    execute(t->right->right, flags & XERROK, xerrok);
 
397
                break;
 
398
 
 
399
        case TCASE:
 
400
                i = 0;
 
401
                ccp = evalstr(t->str, DOTILDE);
 
402
                for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
 
403
                        for (ap = (const char **)t->vars; *ap; ap++) {
 
404
                                if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
 
405
                                    gmatchx(ccp, s, false))) {
 
406
                                        rv = execute(t->left, flags & XERROK,
 
407
                                            xerrok);
 
408
                                        i = 0;
 
409
                                        switch (t->u.charflag) {
 
410
                                        case '&':
 
411
                                                i = 1;
 
412
                                                /* FALLTHROUGH */
 
413
                                        case '|':
 
414
                                                goto TCASE_next;
 
415
                                        }
 
416
                                        goto TCASE_out;
 
417
                                }
 
418
                        }
 
419
                        i = 0;
 
420
 TCASE_next:
 
421
                        /* empty */;
 
422
                }
 
423
 TCASE_out:
 
424
                break;
 
425
 
 
426
        case TBRACE:
 
427
                rv = execute(t->left, flags & XERROK, xerrok);
 
428
                break;
 
429
 
 
430
        case TFUNCT:
 
431
                rv = define(t->str, t);
 
432
                break;
 
433
 
 
434
        case TTIME:
 
435
                /*
 
436
                 * Clear XEXEC so nested execute() call doesn't exit
 
437
                 * (allows "ls -l | time grep foo").
 
438
                 */
 
439
                rv = timex(t, flags & ~XEXEC, xerrok);
 
440
                break;
 
441
 
 
442
        case TEXEC:
 
443
                /* an eval'd TCOM */
 
444
                s = t->args[0];
 
445
                up = makenv();
 
446
                restoresigs();
 
447
                cleanup_proc_env();
 
448
                {
 
449
                        union mksh_ccphack cargs;
 
450
 
 
451
                        cargs.ro = t->args;
 
452
                        execve(t->str, cargs.rw, up);
 
453
                        rv = errno;
 
454
                }
 
455
                if (rv == ENOEXEC)
 
456
                        scriptexec(t, (const char **)up);
 
457
                else
 
458
                        errorf("%s: %s", s, cstrerror(rv));
 
459
        }
 
460
 Break:
 
461
        exstat = rv & 0xFF;
 
462
        if (vp_pipest->flag & INT_L) {
 
463
                unset(vp_pipest, 1);
 
464
                vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY |
 
465
                    ARRAY | INT_U | INT_L;
 
466
                vp_pipest->val.i = rv;
 
467
        }
 
468
 
 
469
        /* restores IO */
 
470
        quitenv(NULL);
 
471
        if ((flags&XEXEC))
 
472
                /* exit child */
 
473
                unwind(LEXIT);
 
474
        if (rv != 0 && !(flags & XERROK) &&
 
475
            (xerrok == NULL || !*xerrok)) {
 
476
                if (Flag(FERREXIT) & 0x80) {
 
477
                        /* inside eval */
 
478
                        Flag(FERREXIT) = 0;
 
479
                } else {
 
480
                        trapsig(ksh_SIGERR);
 
481
                        if (Flag(FERREXIT))
 
482
                                unwind(LERROR);
 
483
                }
 
484
        }
 
485
        return (rv);
 
486
}
 
487
 
 
488
/*
 
489
 * execute simple command
 
490
 */
 
491
 
 
492
static int
 
493
comexec(struct op *t, struct tbl * volatile tp, const char **ap,
 
494
    volatile int flags, volatile int *xerrok)
 
495
{
 
496
        int i;
 
497
        volatile int rv = 0;
 
498
        const char *cp;
 
499
        const char **lastp;
 
500
        /* Must be static (XXX but why?) */
 
501
        static struct op texec;
 
502
        int type_flags;
 
503
        bool keepasn_ok;
 
504
        int fcflags = FC_BI|FC_FUNC|FC_PATH;
 
505
        bool bourne_function_call = false;
 
506
        struct block *l_expand, *l_assign;
 
507
 
 
508
        /*
 
509
         * snag the last argument for $_ XXX not the same as AT&T ksh,
 
510
         * which only seems to set $_ after a newline (but not in
 
511
         * functions/dot scripts, but in interactive and script) -
 
512
         * perhaps save last arg here and set it in shell()?.
 
513
         */
 
514
        if (Flag(FTALKING) && *(lastp = ap)) {
 
515
                while (*++lastp)
 
516
                        ;
 
517
                /* setstr() can't fail here */
 
518
                setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
 
519
                    KSH_RETURN_ERROR);
 
520
        }
 
521
 
 
522
        /**
 
523
         * Deal with the shell builtins builtin, exec and command since
 
524
         * they can be followed by other commands. This must be done before
 
525
         * we know if we should create a local block which must be done
 
526
         * before we can do a path search (in case the assignments change
 
527
         * PATH).
 
528
         * Odd cases:
 
529
         *      FOO=bar exec >/dev/null         FOO is kept but not exported
 
530
         *      FOO=bar exec foobar             FOO is exported
 
531
         *      FOO=bar command exec >/dev/null FOO is neither kept nor exported
 
532
         *      FOO=bar command                 FOO is neither kept nor exported
 
533
         *      PATH=... foobar                 use new PATH in foobar search
 
534
         */
 
535
        keepasn_ok = true;
 
536
        while (tp && tp->type == CSHELL) {
 
537
                /* undo effects of command */
 
538
                fcflags = FC_BI|FC_FUNC|FC_PATH;
 
539
                if (tp->val.f == c_builtin) {
 
540
                        if ((cp = *++ap) == NULL ||
 
541
                            (!strcmp(cp, "--") && (cp = *++ap) == NULL)) {
 
542
                                tp = NULL;
 
543
                                break;
 
544
                        }
 
545
                        if ((tp = findcom(cp, FC_BI)) == NULL)
 
546
                                errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
 
547
                        continue;
 
548
                } else if (tp->val.f == c_exec) {
 
549
                        if (ap[1] == NULL)
 
550
                                break;
 
551
                        ap++;
 
552
                        flags |= XEXEC;
 
553
                } else if (tp->val.f == c_command) {
 
554
                        int optc, saw_p = 0;
 
555
 
 
556
                        /*
 
557
                         * Ugly dealing with options in two places (here
 
558
                         * and in c_command(), but such is life)
 
559
                         */
 
560
                        ksh_getopt_reset(&builtin_opt, 0);
 
561
                        while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
 
562
                                saw_p = 1;
 
563
                        if (optc != EOF)
 
564
                                /* command -vV or something */
 
565
                                break;
 
566
                        /* don't look for functions */
 
567
                        fcflags = FC_BI|FC_PATH;
 
568
                        if (saw_p) {
 
569
                                if (Flag(FRESTRICTED)) {
 
570
                                        warningf(true, "%s: %s",
 
571
                                            "command -p", "restricted");
 
572
                                        rv = 1;
 
573
                                        goto Leave;
 
574
                                }
 
575
                                fcflags |= FC_DEFPATH;
 
576
                        }
 
577
                        ap += builtin_opt.optind;
 
578
                        /*
 
579
                         * POSIX says special builtins lose their status
 
580
                         * if accessed using command.
 
581
                         */
 
582
                        keepasn_ok = false;
 
583
                        if (!ap[0]) {
 
584
                                /* ensure command with no args exits with 0 */
 
585
                                subst_exstat = 0;
 
586
                                break;
 
587
                        }
 
588
#ifndef MKSH_NO_EXTERNAL_CAT
 
589
                } else if (tp->val.f == c_cat) {
 
590
                        /*
 
591
                         * if we have any flags, do not use the builtin
 
592
                         * in theory, we could allow -u, but that would
 
593
                         * mean to use ksh_getopt here and possibly ad-
 
594
                         * ded complexity and more code and isn't worth
 
595
                         * additional hassle (and the builtin must call
 
596
                         * ksh_getopt already but can't come back here)
 
597
                         */
 
598
                        if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
 
599
                            /* argument, begins with -, is not - or -- */
 
600
                            (ap[1][1] != '-' || ap[1][2] != '\0'))
 
601
                                /* don't look for builtins or functions */
 
602
                                fcflags = FC_PATH;
 
603
                        else
 
604
                                /* go on, use the builtin */
 
605
                                break;
 
606
#endif
 
607
                } else if (tp->val.f == c_trap) {
 
608
                        t->u.evalflags &= ~DOTCOMEXEC;
 
609
                        break;
 
610
                } else
 
611
                        break;
 
612
                tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
 
613
        }
 
614
        if (t->u.evalflags & DOTCOMEXEC)
 
615
                flags |= XEXEC;
 
616
        l_expand = e->loc;
 
617
        if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
 
618
                type_flags = 0;
 
619
        else {
 
620
                /* create new variable/function block */
 
621
                newblock();
 
622
                /* ksh functions don't keep assignments, POSIX functions do. */
 
623
                if (keepasn_ok && tp && tp->type == CFUNC &&
 
624
                    !(tp->flag & FKSH)) {
 
625
                        bourne_function_call = true;
 
626
                        type_flags = EXPORT;
 
627
                } else
 
628
                        type_flags = LOCAL|LOCAL_COPY|EXPORT;
 
629
        }
 
630
        l_assign = e->loc;
 
631
        if (Flag(FEXPORT))
 
632
                type_flags |= EXPORT;
 
633
        if (Flag(FXTRACE))
 
634
                change_xtrace(2, false);
 
635
        for (i = 0; t->vars[i]; i++) {
 
636
                /* do NOT lookup in the new var/fn block just created */
 
637
                e->loc = l_expand;
 
638
                cp = evalstr(t->vars[i], DOASNTILDE | DOASNFIELD);
 
639
                e->loc = l_assign;
 
640
                if (Flag(FXTRACE)) {
 
641
                        const char *ccp;
 
642
 
 
643
                        ccp = skip_varname(cp, true);
 
644
                        if (*ccp == '+')
 
645
                                ++ccp;
 
646
                        if (*ccp == '=')
 
647
                                ++ccp;
 
648
                        shf_write(cp, ccp - cp, shl_xtrace);
 
649
                        print_value_quoted(shl_xtrace, ccp);
 
650
                        shf_putc(' ', shl_xtrace);
 
651
                }
 
652
                /* but assign in there as usual */
 
653
                typeset(cp, type_flags, 0, 0, 0);
 
654
                if (bourne_function_call && !(type_flags & EXPORT))
 
655
                        typeset(cp, LOCAL | LOCAL_COPY | EXPORT, 0, 0, 0);
 
656
        }
 
657
 
 
658
        if (Flag(FXTRACE)) {
 
659
                change_xtrace(2, false);
 
660
                if (ap[rv = 0]) {
 
661
 xtrace_ap_loop:
 
662
                        print_value_quoted(shl_xtrace, ap[rv]);
 
663
                        if (ap[++rv]) {
 
664
                                shf_putc(' ', shl_xtrace);
 
665
                                goto xtrace_ap_loop;
 
666
                        }
 
667
                }
 
668
                change_xtrace(1, false);
 
669
        }
 
670
 
 
671
        if ((cp = *ap) == NULL) {
 
672
                rv = subst_exstat;
 
673
                goto Leave;
 
674
        } else if (!tp) {
 
675
                if (Flag(FRESTRICTED) && vstrchr(cp, '/')) {
 
676
                        warningf(true, "%s: %s", cp, "restricted");
 
677
                        rv = 1;
 
678
                        goto Leave;
 
679
                }
 
680
                tp = findcom(cp, fcflags);
 
681
        }
 
682
 
 
683
        switch (tp->type) {
 
684
 
 
685
        /* shell built-in */
 
686
        case CSHELL:
 
687
                rv = call_builtin(tp, (const char **)ap, null);
 
688
                if (!keepasn_ok && tp->val.f == c_shift) {
 
689
                        l_expand->argc = l_assign->argc;
 
690
                        l_expand->argv = l_assign->argv;
 
691
                }
 
692
                break;
 
693
 
 
694
        /* function call */
 
695
        case CFUNC: {
 
696
                volatile unsigned char old_xflag;
 
697
                volatile uint32_t old_inuse;
 
698
                const char * volatile old_kshname;
 
699
 
 
700
                if (!(tp->flag & ISSET)) {
 
701
                        struct tbl *ftp;
 
702
 
 
703
                        if (!tp->u.fpath) {
 
704
                                rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
 
705
                                warningf(true, "%s: %s %s: %s", cp,
 
706
                                    "can't find", "function definition file",
 
707
                                    cstrerror(tp->u2.errnov));
 
708
                                break;
 
709
                        }
 
710
                        if (include(tp->u.fpath, 0, NULL, false) < 0) {
 
711
                                warningf(true, "%s: %s %s %s: %s", cp,
 
712
                                    "can't open", "function definition file",
 
713
                                    tp->u.fpath, cstrerror(errno));
 
714
                                rv = 127;
 
715
                                break;
 
716
                        }
 
717
                        if (!(ftp = findfunc(cp, hash(cp), false)) ||
 
718
                            !(ftp->flag & ISSET)) {
 
719
                                warningf(true, "%s: %s %s", cp,
 
720
                                    "function not defined by", tp->u.fpath);
 
721
                                rv = 127;
 
722
                                break;
 
723
                        }
 
724
                        tp = ftp;
 
725
                }
 
726
 
 
727
                /*
 
728
                 * ksh functions set $0 to function name, POSIX
 
729
                 * functions leave $0 unchanged.
 
730
                 */
 
731
                old_kshname = kshname;
 
732
                if (tp->flag & FKSH)
 
733
                        kshname = ap[0];
 
734
                else
 
735
                        ap[0] = kshname;
 
736
                e->loc->argv = ap;
 
737
                for (i = 0; *ap++ != NULL; i++)
 
738
                        ;
 
739
                e->loc->argc = i - 1;
 
740
                /*
 
741
                 * ksh-style functions handle getopts sanely,
 
742
                 * Bourne/POSIX functions are insane...
 
743
                 */
 
744
                if (tp->flag & FKSH) {
 
745
                        e->loc->flags |= BF_DOGETOPTS;
 
746
                        e->loc->getopts_state = user_opt;
 
747
                        getopts_reset(1);
 
748
                }
 
749
 
 
750
                old_xflag = Flag(FXTRACE) ? 1 : 0;
 
751
                change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
 
752
                    ((tp->flag & TRACE) ? 1 : 0), false);
 
753
                old_inuse = tp->flag & FINUSE;
 
754
                tp->flag |= FINUSE;
 
755
 
 
756
                e->type = E_FUNC;
 
757
                if (!(i = kshsetjmp(e->jbuf))) {
 
758
                        execute(tp->val.t, flags & XERROK, NULL);
 
759
                        i = LRETURN;
 
760
                }
 
761
 
 
762
                kshname = old_kshname;
 
763
                change_xtrace(old_xflag, false);
 
764
                tp->flag = (tp->flag & ~FINUSE) | old_inuse;
 
765
 
 
766
                /*
 
767
                 * Were we deleted while executing? If so, free the
 
768
                 * execution tree. TODO: Unfortunately, the table entry
 
769
                 * is never re-used until the lookup table is expanded.
 
770
                 */
 
771
                if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
 
772
                        if (tp->flag & ALLOC) {
 
773
                                tp->flag &= ~ALLOC;
 
774
                                tfree(tp->val.t, tp->areap);
 
775
                        }
 
776
                        tp->flag = 0;
 
777
                }
 
778
                switch (i) {
 
779
                case LRETURN:
 
780
                case LERROR:
 
781
                        rv = exstat & 0xFF;
 
782
                        break;
 
783
                case LINTR:
 
784
                case LEXIT:
 
785
                case LLEAVE:
 
786
                case LSHELL:
 
787
                        quitenv(NULL);
 
788
                        unwind(i);
 
789
                        /* NOTREACHED */
 
790
                default:
 
791
                        quitenv(NULL);
 
792
                        internal_errorf("%s %d", "CFUNC", i);
 
793
                }
 
794
                break;
 
795
        }
 
796
 
 
797
        /* executable command */
 
798
        case CEXEC:
 
799
        /* tracked alias */
 
800
        case CTALIAS:
 
801
                if (!(tp->flag&ISSET)) {
 
802
                        if (tp->u2.errnov == ENOENT) {
 
803
                                rv = 127;
 
804
                                warningf(true, "%s: %s", cp, "not found");
 
805
                        } else {
 
806
                                rv = 126;
 
807
                                warningf(true, "%s: %s: %s", cp, "can't execute",
 
808
                                    cstrerror(tp->u2.errnov));
 
809
                        }
 
810
                        break;
 
811
                }
 
812
 
 
813
                /* set $_ to programme's full path */
 
814
                /* setstr() can't fail here */
 
815
                setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0),
 
816
                    tp->val.s, KSH_RETURN_ERROR);
 
817
 
 
818
                if (flags&XEXEC) {
 
819
                        j_exit();
 
820
                        if (!(flags&XBGND)
 
821
#ifndef MKSH_UNEMPLOYED
 
822
                            || Flag(FMONITOR)
 
823
#endif
 
824
                            ) {
 
825
                                setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
 
826
                                setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
 
827
                        }
 
828
                }
 
829
 
 
830
                /* to fork we set up a TEXEC node and call execute */
 
831
                texec.type = TEXEC;
 
832
                /* for tprint */
 
833
                texec.left = t;
 
834
                texec.str = tp->val.s;
 
835
                texec.args = ap;
 
836
                rv = exchild(&texec, flags, xerrok, -1);
 
837
                break;
 
838
        }
 
839
 Leave:
 
840
        if (flags & XEXEC) {
 
841
                exstat = rv & 0xFF;
 
842
                unwind(LLEAVE);
 
843
        }
 
844
        return (rv);
 
845
}
 
846
 
 
847
static void
 
848
scriptexec(struct op *tp, const char **ap)
 
849
{
 
850
        const char *sh;
 
851
#ifndef MKSH_SMALL
 
852
        unsigned char *cp;
 
853
        /* 64 == MAXINTERP in MirBSD <sys/param.h> */
 
854
        char buf[64];
 
855
        int fd;
 
856
#endif
 
857
        union mksh_ccphack args, cap;
 
858
 
 
859
        sh = str_val(global("EXECSHELL"));
 
860
        if (sh && *sh)
 
861
                sh = search_path(sh, path, X_OK, NULL);
 
862
        if (!sh || !*sh)
 
863
                sh = MKSH_DEFAULT_EXECSHELL;
 
864
 
 
865
        *tp->args-- = tp->str;
 
866
 
 
867
#ifndef MKSH_SMALL
 
868
        if ((fd = open(tp->str, O_RDONLY | O_BINARY)) >= 0) {
 
869
                /* read first MAXINTERP octets from file */
 
870
                if (read(fd, buf, sizeof(buf)) <= 0)
 
871
                        /* read error -> no good */
 
872
                        buf[0] = '\0';
 
873
                close(fd);
 
874
 
 
875
                /* skip UTF-8 Byte Order Mark, if present */
 
876
                cp = (unsigned char *)buf;
 
877
                if ((cp[0] == 0xEF) && (cp[1] == 0xBB) && (cp[2] == 0xBF))
 
878
                        cp += 3;
 
879
                /* save begin of shebang for later */
 
880
                fd = (char *)cp - buf;          /* either 0 or (if BOM) 3 */
 
881
 
 
882
                /* scan for newline (or CR) or NUL _before_ end of buffer */
 
883
                while ((size_t)((char *)cp - buf) < sizeof(buf))
 
884
                        if (*cp == '\0' || *cp == '\n' || *cp == '\r') {
 
885
                                *cp = '\0';
 
886
                                break;
 
887
                        } else
 
888
                                ++cp;
 
889
                /* if the shebang line is longer than MAXINTERP, bail out */
 
890
                if ((size_t)((char *)cp - buf) >= sizeof(buf))
 
891
                        goto noshebang;
 
892
 
 
893
                /* restore begin of shebang position (buf+0 or buf+3) */
 
894
                cp = (unsigned char *)(buf + fd);
 
895
                /* bail out if read error (above) or no shebang */
 
896
                if ((cp[0] != '#') || (cp[1] != '!'))
 
897
                        goto noshebang;
 
898
 
 
899
                cp += 2;
 
900
                /* skip whitespace before shell name */
 
901
                while (*cp == ' ' || *cp == '\t')
 
902
                        ++cp;
 
903
                /* just whitespace on the line? */
 
904
                if (*cp == '\0')
 
905
                        goto noshebang;
 
906
                /* no, we actually found an interpreter name */
 
907
                sh = (char *)cp;
 
908
                /* look for end of shell/interpreter name */
 
909
                while (*cp != ' ' && *cp != '\t' && *cp != '\0')
 
910
                        ++cp;
 
911
                /* any arguments? */
 
912
                if (*cp) {
 
913
                        *cp++ = '\0';
 
914
                        /* skip spaces before arguments */
 
915
                        while (*cp == ' ' || *cp == '\t')
 
916
                                ++cp;
 
917
                        /* pass it all in ONE argument (historic reasons) */
 
918
                        if (*cp)
 
919
                                *tp->args-- = (char *)cp;
 
920
                }
 
921
 noshebang:
 
922
                if (buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' &&
 
923
                    buf[3] == 'F')
 
924
                        errorf("%s: not executable: %d-bit ELF file", tp->str,
 
925
                            32 * ((uint8_t)buf[4]));
 
926
                fd = buf[0] << 8 | buf[1];
 
927
                if ((fd == /* OMAGIC */ 0407) ||
 
928
                    (fd == /* NMAGIC */ 0410) ||
 
929
                    (fd == /* ZMAGIC */ 0413) ||
 
930
                    (fd == /* QMAGIC */ 0314) ||
 
931
                    (fd == /* ECOFF_I386 */ 0x4C01) ||
 
932
                    (fd == /* ECOFF_M68K */ 0x0150 || fd == 0x5001) ||
 
933
                    (fd == /* ECOFF_SH */   0x0500 || fd == 0x0005) ||
 
934
                    (fd == /* "MZ" */ 0x4D5A) ||
 
935
                    (fd == /* gzip */ 0x1F8B))
 
936
                        errorf("%s: not executable: magic %04X", tp->str, fd);
 
937
        }
 
938
#endif
 
939
        args.ro = tp->args;
 
940
        *args.ro = sh;
 
941
 
 
942
        cap.ro = ap;
 
943
        execve(args.rw[0], args.rw, cap.rw);
 
944
 
 
945
        /* report both the programme that was run and the bogus interpreter */
 
946
        errorf("%s: %s: %s", tp->str, sh, cstrerror(errno));
 
947
}
 
948
 
 
949
int
 
950
shcomexec(const char **wp)
 
951
{
 
952
        struct tbl *tp;
 
953
 
 
954
        tp = ktsearch(&builtins, *wp, hash(*wp));
 
955
        return (call_builtin(tp, wp, "shcomexec"));
 
956
}
 
957
 
 
958
/*
 
959
 * Search function tables for a function. If create set, a table entry
 
960
 * is created if none is found.
 
961
 */
 
962
struct tbl *
 
963
findfunc(const char *name, uint32_t h, bool create)
 
964
{
 
965
        struct block *l;
 
966
        struct tbl *tp = NULL;
 
967
 
 
968
        for (l = e->loc; l; l = l->next) {
 
969
                tp = ktsearch(&l->funs, name, h);
 
970
                if (tp)
 
971
                        break;
 
972
                if (!l->next && create) {
 
973
                        tp = ktenter(&l->funs, name, h);
 
974
                        tp->flag = DEFINED;
 
975
                        tp->type = CFUNC;
 
976
                        tp->val.t = NULL;
 
977
                        break;
 
978
                }
 
979
        }
 
980
        return (tp);
 
981
}
 
982
 
 
983
/*
 
984
 * define function. Returns 1 if function is being undefined (t == 0) and
 
985
 * function did not exist, returns 0 otherwise.
 
986
 */
 
987
int
 
988
define(const char *name, struct op *t)
 
989
{
 
990
        uint32_t nhash;
 
991
        struct tbl *tp;
 
992
        bool was_set = false;
 
993
 
 
994
        nhash = hash(name);
 
995
 
 
996
        if (t != NULL && !tobool(t->u.ksh_func)) {
 
997
                /* drop same-name aliases for POSIX functions */
 
998
                if ((tp = ktsearch(&aliases, name, nhash)))
 
999
                        ktdelete(tp);
 
1000
        }
 
1001
 
 
1002
        while (/* CONSTCOND */ 1) {
 
1003
                tp = findfunc(name, nhash, true);
 
1004
                /* because findfunc:create=true */
 
1005
                mkssert(tp != NULL);
 
1006
 
 
1007
                if (tp->flag & ISSET)
 
1008
                        was_set = true;
 
1009
                /*
 
1010
                 * If this function is currently being executed, we zap
 
1011
                 * this table entry so findfunc() won't see it
 
1012
                 */
 
1013
                if (tp->flag & FINUSE) {
 
1014
                        tp->name[0] = '\0';
 
1015
                        /* ensure it won't be found */
 
1016
                        tp->flag &= ~DEFINED;
 
1017
                        tp->flag |= FDELETE;
 
1018
                } else
 
1019
                        break;
 
1020
        }
 
1021
 
 
1022
        if (tp->flag & ALLOC) {
 
1023
                tp->flag &= ~(ISSET|ALLOC);
 
1024
                tfree(tp->val.t, tp->areap);
 
1025
        }
 
1026
 
 
1027
        if (t == NULL) {
 
1028
                /* undefine */
 
1029
                ktdelete(tp);
 
1030
                return (was_set ? 0 : 1);
 
1031
        }
 
1032
 
 
1033
        tp->val.t = tcopy(t->left, tp->areap);
 
1034
        tp->flag |= (ISSET|ALLOC);
 
1035
        if (t->u.ksh_func)
 
1036
                tp->flag |= FKSH;
 
1037
 
 
1038
        return (0);
 
1039
}
 
1040
 
 
1041
/*
 
1042
 * add builtin
 
1043
 */
 
1044
const char *
 
1045
builtin(const char *name, int (*func) (const char **))
 
1046
{
 
1047
        struct tbl *tp;
 
1048
        uint32_t flag = DEFINED;
 
1049
 
 
1050
        /* see if any flags should be set for this builtin */
 
1051
        while (1) {
 
1052
                if (*name == '=')
 
1053
                        /* command does variable assignment */
 
1054
                        flag |= KEEPASN;
 
1055
                else if (*name == '*')
 
1056
                        /* POSIX special builtin */
 
1057
                        flag |= SPEC_BI;
 
1058
                else
 
1059
                        break;
 
1060
                name++;
 
1061
        }
 
1062
 
 
1063
        tp = ktenter(&builtins, name, hash(name));
 
1064
        tp->flag = flag;
 
1065
        tp->type = CSHELL;
 
1066
        tp->val.f = func;
 
1067
 
 
1068
        return (name);
 
1069
}
 
1070
 
 
1071
/*
 
1072
 * find command
 
1073
 * either function, hashed command, or built-in (in that order)
 
1074
 */
 
1075
struct tbl *
 
1076
findcom(const char *name, int flags)
 
1077
{
 
1078
        static struct tbl temp;
 
1079
        uint32_t h = hash(name);
 
1080
        struct tbl *tp = NULL, *tbi;
 
1081
        /* insert if not found */
 
1082
        unsigned char insert = Flag(FTRACKALL);
 
1083
        /* for function autoloading */
 
1084
        char *fpath;
 
1085
        union mksh_cchack npath;
 
1086
 
 
1087
        if (vstrchr(name, '/')) {
 
1088
                insert = 0;
 
1089
                /* prevent FPATH search below */
 
1090
                flags &= ~FC_FUNC;
 
1091
                goto Search;
 
1092
        }
 
1093
        tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
 
1094
        /*
 
1095
         * POSIX says special builtins first, then functions, then
 
1096
         * regular builtins, then search path...
 
1097
         */
 
1098
        if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
 
1099
                tp = tbi;
 
1100
        if (!tp && (flags & FC_FUNC)) {
 
1101
                tp = findfunc(name, h, false);
 
1102
                if (tp && !(tp->flag & ISSET)) {
 
1103
                        if ((fpath = str_val(global("FPATH"))) == null) {
 
1104
                                tp->u.fpath = NULL;
 
1105
                                tp->u2.errnov = ENOENT;
 
1106
                        } else
 
1107
                                tp->u.fpath = search_path(name, fpath, R_OK,
 
1108
                                    &tp->u2.errnov);
 
1109
                }
 
1110
        }
 
1111
        if (!tp && (flags & FC_NORMBI) && tbi)
 
1112
                tp = tbi;
 
1113
        if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
 
1114
                tp = ktsearch(&taliases, name, h);
 
1115
                if (tp && (tp->flag & ISSET) &&
 
1116
                    ksh_access(tp->val.s, X_OK) != 0) {
 
1117
                        if (tp->flag & ALLOC) {
 
1118
                                tp->flag &= ~ALLOC;
 
1119
                                afree(tp->val.s, APERM);
 
1120
                        }
 
1121
                        tp->flag &= ~ISSET;
 
1122
                }
 
1123
        }
 
1124
 
 
1125
 Search:
 
1126
        if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) &&
 
1127
            (flags & FC_PATH)) {
 
1128
                if (!tp) {
 
1129
                        if (insert && !(flags & FC_DEFPATH)) {
 
1130
                                tp = ktenter(&taliases, name, h);
 
1131
                                tp->type = CTALIAS;
 
1132
                        } else {
 
1133
                                tp = &temp;
 
1134
                                tp->type = CEXEC;
 
1135
                        }
 
1136
                        /* make ~ISSET */
 
1137
                        tp->flag = DEFINED;
 
1138
                }
 
1139
                npath.ro = search_path(name,
 
1140
                    (flags & FC_DEFPATH) ? def_path : path,
 
1141
                    X_OK, &tp->u2.errnov);
 
1142
                if (npath.ro) {
 
1143
                        strdupx(tp->val.s, npath.ro, APERM);
 
1144
                        if (npath.ro != name)
 
1145
                                afree(npath.rw, ATEMP);
 
1146
                        tp->flag |= ISSET|ALLOC;
 
1147
                } else if ((flags & FC_FUNC) &&
 
1148
                    (fpath = str_val(global("FPATH"))) != null &&
 
1149
                    (npath.ro = search_path(name, fpath, R_OK,
 
1150
                    &tp->u2.errnov)) != NULL) {
 
1151
                        /*
 
1152
                         * An undocumented feature of AT&T ksh is that
 
1153
                         * it searches FPATH if a command is not found,
 
1154
                         * even if the command hasn't been set up as an
 
1155
                         * autoloaded function (ie, no typeset -uf).
 
1156
                         */
 
1157
                        tp = &temp;
 
1158
                        tp->type = CFUNC;
 
1159
                        /* make ~ISSET */
 
1160
                        tp->flag = DEFINED;
 
1161
                        tp->u.fpath = npath.ro;
 
1162
                }
 
1163
        }
 
1164
        return (tp);
 
1165
}
 
1166
 
 
1167
/*
 
1168
 * flush executable commands with relative paths
 
1169
 * (just relative or all?)
 
1170
 */
 
1171
void
 
1172
flushcom(bool all)
 
1173
{
 
1174
        struct tbl *tp;
 
1175
        struct tstate ts;
 
1176
 
 
1177
        for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
 
1178
                if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
 
1179
                        if (tp->flag&ALLOC) {
 
1180
                                tp->flag &= ~(ALLOC|ISSET);
 
1181
                                afree(tp->val.s, APERM);
 
1182
                        }
 
1183
                        tp->flag &= ~ISSET;
 
1184
                }
 
1185
}
 
1186
 
 
1187
/* check if path is something we want to find */
 
1188
static int
 
1189
search_access(const char *fn, int mode)
 
1190
{
 
1191
        struct stat sb;
 
1192
 
 
1193
        if (stat(fn, &sb) < 0)
 
1194
                /* file does not exist */
 
1195
                return (ENOENT);
 
1196
        /* LINTED use of access */
 
1197
        if (access(fn, mode) < 0)
 
1198
                /* file exists, but we can't access it */
 
1199
                return (errno);
 
1200
        if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
 
1201
            !(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
 
1202
                /* access(2) may say root can execute everything */
 
1203
                return (S_ISDIR(sb.st_mode) ? EISDIR : EACCES);
 
1204
        return (0);
 
1205
}
 
1206
 
 
1207
/*
 
1208
 * search for command with PATH
 
1209
 */
 
1210
const char *
 
1211
search_path(const char *name, const char *lpath,
 
1212
    /* R_OK or X_OK */
 
1213
    int mode,
 
1214
    /* set if candidate found, but not suitable */
 
1215
    int *errnop)
 
1216
{
 
1217
        const char *sp, *p;
 
1218
        char *xp;
 
1219
        XString xs;
 
1220
        size_t namelen;
 
1221
        int ec = 0, ev;
 
1222
 
 
1223
        if (vstrchr(name, '/')) {
 
1224
                if ((ec = search_access(name, mode)) == 0) {
 
1225
 search_path_ok:
 
1226
                        if (errnop)
 
1227
                                *errnop = 0;
 
1228
                        return (name);
 
1229
                }
 
1230
                goto search_path_err;
 
1231
        }
 
1232
 
 
1233
        namelen = strlen(name) + 1;
 
1234
        Xinit(xs, xp, 128, ATEMP);
 
1235
 
 
1236
        sp = lpath;
 
1237
        while (sp != NULL) {
 
1238
                xp = Xstring(xs, xp);
 
1239
                if (!(p = cstrchr(sp, ':')))
 
1240
                        p = sp + strlen(sp);
 
1241
                if (p != sp) {
 
1242
                        XcheckN(xs, xp, p - sp);
 
1243
                        memcpy(xp, sp, p - sp);
 
1244
                        xp += p - sp;
 
1245
                        *xp++ = '/';
 
1246
                }
 
1247
                sp = p;
 
1248
                XcheckN(xs, xp, namelen);
 
1249
                memcpy(xp, name, namelen);
 
1250
                if ((ev = search_access(Xstring(xs, xp), mode)) == 0) {
 
1251
                        name = Xclose(xs, xp + namelen);
 
1252
                        goto search_path_ok;
 
1253
                }
 
1254
                /* accumulate non-ENOENT errors only */
 
1255
                if (ev != ENOENT && ec == 0)
 
1256
                        ec = ev;
 
1257
                if (*sp++ == '\0')
 
1258
                        sp = NULL;
 
1259
        }
 
1260
        Xfree(xs, xp);
 
1261
 search_path_err:
 
1262
        if (errnop)
 
1263
                *errnop = ec ? ec : ENOENT;
 
1264
        return (NULL);
 
1265
}
 
1266
 
 
1267
static int
 
1268
call_builtin(struct tbl *tp, const char **wp, const char *where)
 
1269
{
 
1270
        int rv;
 
1271
 
 
1272
        if (!tp)
 
1273
                internal_errorf("%s: %s", where, wp[0]);
 
1274
        builtin_argv0 = wp[0];
 
1275
        builtin_flag = tp->flag;
 
1276
        shf_reopen(1, SHF_WR, shl_stdout);
 
1277
        shl_stdout_ok = true;
 
1278
        ksh_getopt_reset(&builtin_opt, GF_ERROR);
 
1279
        rv = (*tp->val.f)(wp);
 
1280
        shf_flush(shl_stdout);
 
1281
        shl_stdout_ok = false;
 
1282
        builtin_flag = 0;
 
1283
        builtin_argv0 = NULL;
 
1284
        return (rv);
 
1285
}
 
1286
 
 
1287
/*
 
1288
 * set up redirection, saving old fds in e->savefd
 
1289
 */
 
1290
static int
 
1291
iosetup(struct ioword *iop, struct tbl *tp)
 
1292
{
 
1293
        int u = -1;
 
1294
        char *cp = iop->name;
 
1295
        int iotype = iop->flag & IOTYPE;
 
1296
        bool do_open = true, do_close = false;
 
1297
        int flags = 0;
 
1298
        struct ioword iotmp;
 
1299
        struct stat statb;
 
1300
 
 
1301
        if (iotype != IOHERE)
 
1302
                cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
 
1303
 
 
1304
        /* Used for tracing and error messages to print expanded cp */
 
1305
        iotmp = *iop;
 
1306
        iotmp.name = (iotype == IOHERE) ? NULL : cp;
 
1307
        iotmp.flag |= IONAMEXP;
 
1308
 
 
1309
        if (Flag(FXTRACE)) {
 
1310
                change_xtrace(2, false);
 
1311
                fptreef(shl_xtrace, 0, "%R", &iotmp);
 
1312
                change_xtrace(1, false);
 
1313
        }
 
1314
 
 
1315
        switch (iotype) {
 
1316
        case IOREAD:
 
1317
                flags = O_RDONLY;
 
1318
                break;
 
1319
 
 
1320
        case IOCAT:
 
1321
                flags = O_WRONLY | O_APPEND | O_CREAT;
 
1322
                break;
 
1323
 
 
1324
        case IOWRITE:
 
1325
                flags = O_WRONLY | O_CREAT | O_TRUNC;
 
1326
                /*
 
1327
                 * The stat() is here to allow redirections to
 
1328
                 * things like /dev/null without error.
 
1329
                 */
 
1330
                if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
 
1331
                    (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
 
1332
                        flags |= O_EXCL;
 
1333
                break;
 
1334
 
 
1335
        case IORDWR:
 
1336
                flags = O_RDWR | O_CREAT;
 
1337
                break;
 
1338
 
 
1339
        case IOHERE:
 
1340
                do_open = false;
 
1341
                /* herein() returns -2 if error has been printed */
 
1342
                u = herein(iop, NULL);
 
1343
                /* cp may have wrong name */
 
1344
                break;
 
1345
 
 
1346
        case IODUP: {
 
1347
                const char *emsg;
 
1348
 
 
1349
                do_open = false;
 
1350
                if (*cp == '-' && !cp[1]) {
 
1351
                        /* prevent error return below */
 
1352
                        u = 1009;
 
1353
                        do_close = true;
 
1354
                } else if ((u = check_fd(cp,
 
1355
                    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
 
1356
                    &emsg)) < 0) {
 
1357
                        char *sp;
 
1358
 
 
1359
                        warningf(true, "%s: %s",
 
1360
                            (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
 
1361
                        afree(sp, ATEMP);
 
1362
                        return (-1);
 
1363
                }
 
1364
                if (u == iop->unit)
 
1365
                        /* "dup from" == "dup to" */
 
1366
                        return (0);
 
1367
                break;
 
1368
            }
 
1369
        }
 
1370
 
 
1371
        if (do_open) {
 
1372
                if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
 
1373
                        warningf(true, "%s: %s", cp, "restricted");
 
1374
                        return (-1);
 
1375
                }
 
1376
                u = open(cp, flags | O_BINARY, 0666);
 
1377
        }
 
1378
        if (u < 0) {
 
1379
                /* herein() may already have printed message */
 
1380
                if (u == -1) {
 
1381
                        u = errno;
 
1382
                        warningf(true, "can't %s %s: %s",
 
1383
                            iotype == IODUP ? "dup" :
 
1384
                            (iotype == IOREAD || iotype == IOHERE) ?
 
1385
                            "open" : "create", cp, cstrerror(u));
 
1386
                }
 
1387
                return (-1);
 
1388
        }
 
1389
        /* Do not save if it has already been redirected (i.e. "cat >x >y"). */
 
1390
        if (e->savefd[iop->unit] == 0) {
 
1391
                /* If these are the same, it means unit was previously closed */
 
1392
                if (u == iop->unit)
 
1393
                        e->savefd[iop->unit] = -1;
 
1394
                else
 
1395
                        /*
 
1396
                         * c_exec() assumes e->savefd[fd] set for any
 
1397
                         * redirections. Ask savefd() not to close iop->unit;
 
1398
                         * this allows error messages to be seen if iop->unit
 
1399
                         * is 2; also means we can't lose the fd (eg, both
 
1400
                         * dup2 below and dup2 in restfd() failing).
 
1401
                         */
 
1402
                        e->savefd[iop->unit] = savefd(iop->unit);
 
1403
        }
 
1404
 
 
1405
        if (do_close)
 
1406
                close(iop->unit);
 
1407
        else if (u != iop->unit) {
 
1408
                if (ksh_dup2(u, iop->unit, true) < 0) {
 
1409
                        int eno;
 
1410
                        char *sp;
 
1411
 
 
1412
                        eno = errno;
 
1413
                        warningf(true, "%s %s %s",
 
1414
                            "can't finish (dup) redirection",
 
1415
                            (sp = snptreef(NULL, 32, "%R", &iotmp)),
 
1416
                            cstrerror(eno));
 
1417
                        afree(sp, ATEMP);
 
1418
                        if (iotype != IODUP)
 
1419
                                close(u);
 
1420
                        return (-1);
 
1421
                }
 
1422
                if (iotype != IODUP)
 
1423
                        close(u);
 
1424
                /*
 
1425
                 * Touching any co-process fd in an empty exec
 
1426
                 * causes the shell to close its copies
 
1427
                 */
 
1428
                else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
 
1429
                        if (iop->flag & IORDUP)
 
1430
                                /* possible exec <&p */
 
1431
                                coproc_read_close(u);
 
1432
                        else
 
1433
                                /* possible exec >&p */
 
1434
                                coproc_write_close(u);
 
1435
                }
 
1436
        }
 
1437
        if (u == 2)
 
1438
                /* Clear any write errors */
 
1439
                shf_reopen(2, SHF_WR, shl_out);
 
1440
        return (0);
 
1441
}
 
1442
 
 
1443
/*
 
1444
 * Process here documents by providing the content, either as
 
1445
 * result (globally allocated) string or in a temp file; if
 
1446
 * unquoted, the string is expanded first.
 
1447
 */
 
1448
static int
 
1449
hereinval(const char *content, int sub, char **resbuf, struct shf *shf)
 
1450
{
 
1451
        const char * volatile ccp = content;
 
1452
        struct source *s, *osource;
 
1453
 
 
1454
        osource = source;
 
1455
        newenv(E_ERRH);
 
1456
        if (kshsetjmp(e->jbuf)) {
 
1457
                source = osource;
 
1458
                quitenv(shf);
 
1459
                /* special to iosetup(): don't print error */
 
1460
                return (-2);
 
1461
        }
 
1462
        if (sub) {
 
1463
                /* do substitutions on the content of heredoc */
 
1464
                s = pushs(SSTRING, ATEMP);
 
1465
                s->start = s->str = ccp;
 
1466
                source = s;
 
1467
                if (yylex(sub) != LWORD)
 
1468
                        internal_errorf("%s: %s", "herein", "yylex");
 
1469
                source = osource;
 
1470
                ccp = evalstr(yylval.cp, 0);
 
1471
        }
 
1472
 
 
1473
        if (resbuf == NULL)
 
1474
                shf_puts(ccp, shf);
 
1475
        else
 
1476
                strdupx(*resbuf, ccp, APERM);
 
1477
 
 
1478
        quitenv(NULL);
 
1479
        return (0);
 
1480
}
 
1481
 
 
1482
static int
 
1483
herein(struct ioword *iop, char **resbuf)
 
1484
{
 
1485
        int fd = -1;
 
1486
        struct shf *shf;
 
1487
        struct temp *h;
 
1488
        int i;
 
1489
 
 
1490
        /* ksh -c 'cat << EOF' can cause this... */
 
1491
        if (iop->heredoc == NULL) {
 
1492
                warningf(true, "%s missing", "here document");
 
1493
                /* special to iosetup(): don't print error */
 
1494
                return (-2);
 
1495
        }
 
1496
 
 
1497
        /* lexer substitution flags */
 
1498
        i = (iop->flag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
 
1499
 
 
1500
        /* skip all the fd setup if we just want the value */
 
1501
        if (resbuf != NULL)
 
1502
                return (hereinval(iop->heredoc, i, resbuf, NULL));
 
1503
 
 
1504
        /*
 
1505
         * Create temp file to hold content (done before newenv
 
1506
         * so temp doesn't get removed too soon).
 
1507
         */
 
1508
        h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
 
1509
        if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY | O_BINARY, 0)) < 0) {
 
1510
                i = errno;
 
1511
                warningf(true, "can't %s temporary file %s: %s",
 
1512
                    !shf ? "create" : "open", h->tffn, cstrerror(i));
 
1513
                if (shf)
 
1514
                        shf_close(shf);
 
1515
                /* special to iosetup(): don't print error */
 
1516
                return (-2);
 
1517
        }
 
1518
 
 
1519
        if (hereinval(iop->heredoc, i, NULL, shf) == -2) {
 
1520
                close(fd);
 
1521
                /* special to iosetup(): don't print error */
 
1522
                return (-2);
 
1523
        }
 
1524
 
 
1525
        if (shf_close(shf) == EOF) {
 
1526
                i = errno;
 
1527
                close(fd);
 
1528
                warningf(true, "can't %s temporary file %s: %s",
 
1529
                    "write", h->tffn, cstrerror(i));
 
1530
                /* special to iosetup(): don't print error */
 
1531
                return (-2);
 
1532
        }
 
1533
 
 
1534
        return (fd);
 
1535
}
 
1536
 
 
1537
/*
 
1538
 *      ksh special - the select command processing section
 
1539
 *      print the args in column form - assuming that we can
 
1540
 */
 
1541
static const char *
 
1542
do_selectargs(const char **ap, bool print_menu)
 
1543
{
 
1544
        static const char *read_args[] = {
 
1545
                "read", "-r", "REPLY", NULL
 
1546
        };
 
1547
        char *s;
 
1548
        int i, argct;
 
1549
 
 
1550
        for (argct = 0; ap[argct]; argct++)
 
1551
                ;
 
1552
        while (/* CONSTCOND */ 1) {
 
1553
                /*-
 
1554
                 * Menu is printed if
 
1555
                 *      - this is the first time around the select loop
 
1556
                 *      - the user enters a blank line
 
1557
                 *      - the REPLY parameter is empty
 
1558
                 */
 
1559
                if (print_menu || !*str_val(global("REPLY")))
 
1560
                        pr_menu(ap);
 
1561
                shellf("%s", str_val(global("PS3")));
 
1562
                if (call_builtin(findcom("read", FC_BI), read_args, Tselect))
 
1563
                        return (NULL);
 
1564
                s = str_val(global("REPLY"));
 
1565
                if (*s && getn(s, &i))
 
1566
                        return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
 
1567
                print_menu = true;
 
1568
        }
 
1569
}
 
1570
 
 
1571
struct select_menu_info {
 
1572
        const char * const *args;
 
1573
        int num_width;
 
1574
};
 
1575
 
 
1576
/* format a single select menu item */
 
1577
static char *
 
1578
select_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
 
1579
{
 
1580
        const struct select_menu_info *smi =
 
1581
            (const struct select_menu_info *)arg;
 
1582
 
 
1583
        shf_snprintf(buf, buflen, "%*u) %s",
 
1584
            smi->num_width, i + 1, smi->args[i]);
 
1585
        return (buf);
 
1586
}
 
1587
 
 
1588
/*
 
1589
 *      print a select style menu
 
1590
 */
 
1591
void
 
1592
pr_menu(const char * const *ap)
 
1593
{
 
1594
        struct select_menu_info smi;
 
1595
        const char * const *pp;
 
1596
        size_t acols = 0, aocts = 0, i;
 
1597
        unsigned int n;
 
1598
 
 
1599
        /*
 
1600
         * width/column calculations were done once and saved, but this
 
1601
         * means select can't be used recursively so we re-calculate
 
1602
         * each time (could save in a structure that is returned, but
 
1603
         * it's probably not worth the bother)
 
1604
         */
 
1605
 
 
1606
        /*
 
1607
         * get dimensions of the list
 
1608
         */
 
1609
        for (n = 0, pp = ap; *pp; n++, pp++) {
 
1610
                i = strlen(*pp);
 
1611
                if (i > aocts)
 
1612
                        aocts = i;
 
1613
                i = utf_mbswidth(*pp);
 
1614
                if (i > acols)
 
1615
                        acols = i;
 
1616
        }
 
1617
 
 
1618
        /*
 
1619
         * we will print an index of the form "%d) " in front of
 
1620
         * each entry, so get the maximum width of this
 
1621
         */
 
1622
        for (i = n, smi.num_width = 1; i >= 10; i /= 10)
 
1623
                smi.num_width++;
 
1624
 
 
1625
        smi.args = ap;
 
1626
        print_columns(shl_out, n, select_fmt_entry, (void *)&smi,
 
1627
            smi.num_width + 2 + aocts, smi.num_width + 2 + acols,
 
1628
            true);
 
1629
}
 
1630
 
 
1631
static char *
 
1632
plain_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
 
1633
{
 
1634
        strlcpy(buf, ((const char * const *)arg)[i], buflen);
 
1635
        return (buf);
 
1636
}
 
1637
 
 
1638
void
 
1639
pr_list(char * const *ap)
 
1640
{
 
1641
        size_t acols = 0, aocts = 0, i;
 
1642
        unsigned int n;
 
1643
        char * const *pp;
 
1644
 
 
1645
        for (n = 0, pp = ap; *pp; n++, pp++) {
 
1646
                i = strlen(*pp);
 
1647
                if (i > aocts)
 
1648
                        aocts = i;
 
1649
                i = utf_mbswidth(*pp);
 
1650
                if (i > acols)
 
1651
                        acols = i;
 
1652
        }
 
1653
 
 
1654
        print_columns(shl_out, n, plain_fmt_entry, (const void *)ap,
 
1655
            aocts, acols, false);
 
1656
}
 
1657
 
 
1658
/*
 
1659
 *      [[ ... ]] evaluation routines
 
1660
 */
 
1661
 
 
1662
/*
 
1663
 * Test if the current token is a whatever. Accepts the current token if
 
1664
 * it is. Returns 0 if it is not, non-zero if it is (in the case of
 
1665
 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
 
1666
 */
 
1667
static Test_op
 
1668
dbteste_isa(Test_env *te, Test_meta meta)
 
1669
{
 
1670
        Test_op ret = TO_NONOP;
 
1671
        bool uqword;
 
1672
        const char *p;
 
1673
 
 
1674
        if (!*te->pos.wp)
 
1675
                return (meta == TM_END ? TO_NONNULL : TO_NONOP);
 
1676
 
 
1677
        /* unquoted word? */
 
1678
        for (p = *te->pos.wp; *p == CHAR; p += 2)
 
1679
                ;
 
1680
        uqword = *p == EOS;
 
1681
 
 
1682
        if (meta == TM_UNOP || meta == TM_BINOP) {
 
1683
                if (uqword) {
 
1684
                        /* longer than the longest operator */
 
1685
                        char buf[8];
 
1686
                        char *q = buf;
 
1687
 
 
1688
                        p = *te->pos.wp;
 
1689
                        while (*p++ == CHAR &&
 
1690
                            (size_t)(q - buf) < sizeof(buf) - 1)
 
1691
                                *q++ = *p++;
 
1692
                        *q = '\0';
 
1693
                        ret = test_isop(meta, buf);
 
1694
                }
 
1695
        } else if (meta == TM_END)
 
1696
                ret = TO_NONOP;
 
1697
        else
 
1698
                ret = (uqword && !strcmp(*te->pos.wp,
 
1699
                    dbtest_tokens[(int)meta])) ? TO_NONNULL : TO_NONOP;
 
1700
 
 
1701
        /* Accept the token? */
 
1702
        if (ret != TO_NONOP)
 
1703
                te->pos.wp++;
 
1704
 
 
1705
        return (ret);
 
1706
}
 
1707
 
 
1708
static const char *
 
1709
dbteste_getopnd(Test_env *te, Test_op op, bool do_eval)
 
1710
{
 
1711
        const char *s = *te->pos.wp;
 
1712
 
 
1713
        if (!s)
 
1714
                return (NULL);
 
1715
 
 
1716
        te->pos.wp++;
 
1717
 
 
1718
        if (!do_eval)
 
1719
                return (null);
 
1720
 
 
1721
        if (op == TO_STEQL || op == TO_STNEQ)
 
1722
                s = evalstr(s, DOTILDE | DOPAT);
 
1723
        else
 
1724
                s = evalstr(s, DOTILDE);
 
1725
 
 
1726
        return (s);
 
1727
}
 
1728
 
 
1729
static void
 
1730
dbteste_error(Test_env *te, int offset, const char *msg)
 
1731
{
 
1732
        te->flags |= TEF_ERROR;
 
1733
        internal_warningf("dbteste_error: %s (offset %d)", msg, offset);
 
1734
}