~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to dash/eval.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 1993
 
3
 *      The Regents of the University of California.  All rights reserved.
 
4
 * Copyright (c) 1997-2005
 
5
 *      Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
 
6
 *
 
7
 * This code is derived from software contributed to Berkeley by
 
8
 * Kenneth Almquist.
 
9
 *
 
10
 * Redistribution and use in source and binary forms, with or without
 
11
 * modification, are permitted provided that the following conditions
 
12
 * are met:
 
13
 * 1. Redistributions of source code must retain the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer.
 
15
 * 2. Redistributions in binary form must reproduce the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer in the
 
17
 *    documentation and/or other materials provided with the distribution.
 
18
 * 3. Neither the name of the University nor the names of its contributors
 
19
 *    may be used to endorse or promote products derived from this software
 
20
 *    without specific prior written permission.
 
21
 *
 
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
32
 * SUCH DAMAGE.
 
33
 */
 
34
 
 
35
#include <stdlib.h>
 
36
#include <signal.h>
 
37
#include <unistd.h>
 
38
#include <sys/types.h>
 
39
 
 
40
/*
 
41
 * Evaluate a command.
 
42
 */
 
43
 
 
44
#include "shell.h"
 
45
#include "nodes.h"
 
46
#include "syntax.h"
 
47
#include "expand.h"
 
48
#include "parser.h"
 
49
#include "jobs.h"
 
50
#include "eval.h"
 
51
#include "builtins.h"
 
52
#include "options.h"
 
53
#include "exec.h"
 
54
#include "redir.h"
 
55
#include "input.h"
 
56
#include "output.h"
 
57
#include "trap.h"
 
58
#include "var.h"
 
59
#include "memalloc.h"
 
60
#include "error.h"
 
61
#include "show.h"
 
62
#include "mystring.h"
 
63
#ifndef SMALL
 
64
#include "myhistedit.h"
 
65
#endif
 
66
 
 
67
 
 
68
/* flags in argument to evaltree */
 
69
#define EV_EXIT 01              /* exit after evaluating tree */
 
70
#define EV_TESTED 02            /* exit status is checked; ignore -e flag */
 
71
#define EV_BACKCMD 04           /* command executing within back quotes */
 
72
 
 
73
int evalskip;                   /* set if we are skipping commands */
 
74
STATIC int skipcount;           /* number of levels to skip */
 
75
MKINIT int loopnest;            /* current loop nesting level */
 
76
static int funcnest;            /* depth of function calls */
 
77
 
 
78
 
 
79
char *commandname;
 
80
struct strlist *cmdenviron;
 
81
int exitstatus;                 /* exit status of last command */
 
82
int back_exitstatus;            /* exit status of backquoted command */
 
83
 
 
84
 
 
85
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
 
86
STATIC
 
87
#endif
 
88
void evaltreenr(union node *, int) __attribute__ ((__noreturn__));
 
89
STATIC void evalloop(union node *, int);
 
90
STATIC void evalfor(union node *, int);
 
91
STATIC void evalcase(union node *, int);
 
92
STATIC void evalsubshell(union node *, int);
 
93
STATIC void expredir(union node *);
 
94
STATIC void evalpipe(union node *, int);
 
95
#ifdef notyet
 
96
STATIC void evalcommand(union node *, int, struct backcmd *);
 
97
#else
 
98
STATIC void evalcommand(union node *, int);
 
99
#endif
 
100
STATIC int evalbltin(const struct builtincmd *, int, char **);
 
101
STATIC int evalfun(struct funcnode *, int, char **, int);
 
102
STATIC void prehash(union node *);
 
103
STATIC int eprintlist(struct output *, struct strlist *, int);
 
104
STATIC int bltincmd(int, char **);
 
105
 
 
106
 
 
107
STATIC const struct builtincmd bltin = {
 
108
        name: nullstr,
 
109
        builtin: bltincmd
 
110
};
 
111
 
 
112
 
 
113
/*
 
114
 * Called to reset things after an exception.
 
115
 */
 
116
 
 
117
#ifdef mkinit
 
118
INCLUDE "eval.h"
 
119
 
 
120
RESET {
 
121
        evalskip = 0;
 
122
        loopnest = 0;
 
123
}
 
124
#endif
 
125
 
 
126
 
 
127
 
 
128
/*
 
129
 * The eval commmand.
 
130
 */
 
131
 
 
132
int
 
133
evalcmd(int argc, char **argv)
 
134
{
 
135
        char *p;
 
136
        char *concat;
 
137
        char **ap;
 
138
 
 
139
        if (argc > 1) {
 
140
                p = argv[1];
 
141
                if (argc > 2) {
 
142
                        STARTSTACKSTR(concat);
 
143
                        ap = argv + 2;
 
144
                        for (;;) {
 
145
                                concat = stputs(p, concat);
 
146
                                if ((p = *ap++) == NULL)
 
147
                                        break;
 
148
                                STPUTC(' ', concat);
 
149
                        }
 
150
                        STPUTC('\0', concat);
 
151
                        p = grabstackstr(concat);
 
152
                }
 
153
                evalstring(p, ~SKIPEVAL);
 
154
                
 
155
        }
 
156
        return exitstatus;
 
157
}
 
158
 
 
159
 
 
160
/*
 
161
 * Execute a command or commands contained in a string.
 
162
 */
 
163
 
 
164
int
 
165
evalstring(char *s, int mask)
 
166
{
 
167
        union node *n;
 
168
        struct stackmark smark;
 
169
        int skip;
 
170
 
 
171
        setinputstring(s);
 
172
        setstackmark(&smark);
 
173
 
 
174
        skip = 0;
 
175
        while ((n = parsecmd(0)) != NEOF) {
 
176
                evaltree(n, 0);
 
177
                popstackmark(&smark);
 
178
                skip = evalskip;
 
179
                if (skip)
 
180
                        break;
 
181
        }
 
182
        popfile();
 
183
 
 
184
        skip &= mask;
 
185
        evalskip = skip;
 
186
        return skip;
 
187
}
 
188
 
 
189
 
 
190
 
 
191
/*
 
192
 * Evaluate a parse tree.  The value is left in the global variable
 
193
 * exitstatus.
 
194
 */
 
195
 
 
196
void
 
197
evaltree(union node *n, int flags)
 
198
{
 
199
        int checkexit = 0;
 
200
        void (*evalfn)(union node *, int);
 
201
        unsigned isor;
 
202
        int status;
 
203
        if (n == NULL) {
 
204
                TRACE(("evaltree(NULL) called\n"));
 
205
                goto out;
 
206
        }
 
207
#ifndef SMALL
 
208
        displayhist = 1;        /* show history substitutions done with fc */
 
209
#endif
 
210
        TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
 
211
            getpid(), n, n->type, flags));
 
212
        switch (n->type) {
 
213
        default:
 
214
#ifdef DEBUG
 
215
                out1fmt("Node type = %d\n", n->type);
 
216
#ifndef USE_GLIBC_STDIO
 
217
                flushout(out1);
 
218
#endif
 
219
                break;
 
220
#endif
 
221
        case NNOT:
 
222
                evaltree(n->nnot.com, EV_TESTED);
 
223
                status = !exitstatus;
 
224
                goto setstatus;
 
225
        case NREDIR:
 
226
                expredir(n->nredir.redirect);
 
227
                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
 
228
                if (!status) {
 
229
                        evaltree(n->nredir.n, flags & EV_TESTED);
 
230
                        status = exitstatus;
 
231
                }
 
232
                popredir(0);
 
233
                goto setstatus;
 
234
        case NCMD:
 
235
#ifdef notyet
 
236
                if (eflag && !(flags & EV_TESTED))
 
237
                        checkexit = ~0;
 
238
                evalcommand(n, flags, (struct backcmd *)NULL);
 
239
                break;
 
240
#else
 
241
                evalfn = evalcommand;
 
242
checkexit:
 
243
                if (eflag && !(flags & EV_TESTED))
 
244
                        checkexit = ~0;
 
245
                goto calleval;
 
246
#endif
 
247
        case NFOR:
 
248
                evalfn = evalfor;
 
249
                goto calleval;
 
250
        case NWHILE:
 
251
        case NUNTIL:
 
252
                evalfn = evalloop;
 
253
                goto calleval;
 
254
        case NSUBSHELL:
 
255
        case NBACKGND:
 
256
                evalfn = evalsubshell;
 
257
                goto calleval;
 
258
        case NPIPE:
 
259
                evalfn = evalpipe;
 
260
#ifdef notyet
 
261
                if (eflag && !(flags & EV_TESTED))
 
262
                        checkexit = ~0;
 
263
                goto calleval;
 
264
#else
 
265
                goto checkexit;
 
266
#endif
 
267
        case NCASE:
 
268
                evalfn = evalcase;
 
269
                goto calleval;
 
270
        case NAND:
 
271
        case NOR:
 
272
        case NSEMI:
 
273
#if NAND + 1 != NOR
 
274
#error NAND + 1 != NOR
 
275
#endif
 
276
#if NOR + 1 != NSEMI
 
277
#error NOR + 1 != NSEMI
 
278
#endif
 
279
                isor = n->type - NAND;
 
280
                evaltree(
 
281
                        n->nbinary.ch1,
 
282
                        (flags | ((isor >> 1) - 1)) & EV_TESTED
 
283
                );
 
284
                if (!exitstatus == isor)
 
285
                        break;
 
286
                if (!evalskip) {
 
287
                        n = n->nbinary.ch2;
 
288
evaln:
 
289
                        evalfn = evaltree;
 
290
calleval:
 
291
                        evalfn(n, flags);
 
292
                        break;
 
293
                }
 
294
                break;
 
295
        case NIF:
 
296
                evaltree(n->nif.test, EV_TESTED);
 
297
                if (evalskip)
 
298
                        break;
 
299
                if (exitstatus == 0) {
 
300
                        n = n->nif.ifpart;
 
301
                        goto evaln;
 
302
                } else if (n->nif.elsepart) {
 
303
                        n = n->nif.elsepart;
 
304
                        goto evaln;
 
305
                }
 
306
                goto success;
 
307
        case NDEFUN:
 
308
                defun(n->narg.text, n->narg.next);
 
309
success:
 
310
                status = 0;
 
311
setstatus:
 
312
                exitstatus = status;
 
313
                break;
 
314
        }
 
315
out:
 
316
        if ((checkexit & exitstatus))
 
317
                evalskip |= SKIPEVAL;
 
318
        else if (pendingsigs && dotrap())
 
319
                goto exexit;
 
320
 
 
321
        if (flags & EV_EXIT) {
 
322
exexit:
 
323
                exraise(EXEXIT);
 
324
        }
 
325
}
 
326
 
 
327
 
 
328
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
 
329
STATIC
 
330
#endif
 
331
void evaltreenr(union node *, int) __attribute__ ((alias("evaltree")));
 
332
 
 
333
 
 
334
STATIC void
 
335
evalloop(union node *n, int flags)
 
336
{
 
337
        int status;
 
338
 
 
339
        loopnest++;
 
340
        status = 0;
 
341
        flags &= EV_TESTED;
 
342
        for (;;) {
 
343
                int i;
 
344
 
 
345
                evaltree(n->nbinary.ch1, EV_TESTED);
 
346
                if (evalskip) {
 
347
skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
 
348
                                evalskip = 0;
 
349
                                continue;
 
350
                        }
 
351
                        if (evalskip == SKIPBREAK && --skipcount <= 0)
 
352
                                evalskip = 0;
 
353
                        break;
 
354
                }
 
355
                i = exitstatus;
 
356
                if (n->type != NWHILE)
 
357
                        i = !i;
 
358
                if (i != 0)
 
359
                        break;
 
360
                evaltree(n->nbinary.ch2, flags);
 
361
                status = exitstatus;
 
362
                if (evalskip)
 
363
                        goto skipping;
 
364
        }
 
365
        loopnest--;
 
366
        exitstatus = status;
 
367
}
 
368
 
 
369
 
 
370
 
 
371
STATIC void
 
372
evalfor(union node *n, int flags)
 
373
{
 
374
        struct arglist arglist;
 
375
        union node *argp;
 
376
        struct strlist *sp;
 
377
        struct stackmark smark;
 
378
 
 
379
        setstackmark(&smark);
 
380
        arglist.lastp = &arglist.list;
 
381
        for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
 
382
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
 
383
                /* XXX */
 
384
                if (evalskip)
 
385
                        goto out;
 
386
        }
 
387
        *arglist.lastp = NULL;
 
388
 
 
389
        exitstatus = 0;
 
390
        loopnest++;
 
391
        flags &= EV_TESTED;
 
392
        for (sp = arglist.list ; sp ; sp = sp->next) {
 
393
                setvar(n->nfor.var, sp->text, 0);
 
394
                evaltree(n->nfor.body, flags);
 
395
                if (evalskip) {
 
396
                        if (evalskip == SKIPCONT && --skipcount <= 0) {
 
397
                                evalskip = 0;
 
398
                                continue;
 
399
                        }
 
400
                        if (evalskip == SKIPBREAK && --skipcount <= 0)
 
401
                                evalskip = 0;
 
402
                        break;
 
403
                }
 
404
        }
 
405
        loopnest--;
 
406
out:
 
407
        popstackmark(&smark);
 
408
}
 
409
 
 
410
 
 
411
 
 
412
STATIC void
 
413
evalcase(union node *n, int flags)
 
414
{
 
415
        union node *cp;
 
416
        union node *patp;
 
417
        struct arglist arglist;
 
418
        struct stackmark smark;
 
419
 
 
420
        setstackmark(&smark);
 
421
        arglist.lastp = &arglist.list;
 
422
        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
 
423
        exitstatus = 0;
 
424
        for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
 
425
                for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
 
426
                        if (casematch(patp, arglist.list->text)) {
 
427
                                if (evalskip == 0) {
 
428
                                        evaltree(cp->nclist.body, flags);
 
429
                                }
 
430
                                goto out;
 
431
                        }
 
432
                }
 
433
        }
 
434
out:
 
435
        popstackmark(&smark);
 
436
}
 
437
 
 
438
 
 
439
 
 
440
/*
 
441
 * Kick off a subshell to evaluate a tree.
 
442
 */
 
443
 
 
444
STATIC void
 
445
evalsubshell(union node *n, int flags)
 
446
{
 
447
        struct job *jp;
 
448
        int backgnd = (n->type == NBACKGND);
 
449
        int status;
 
450
 
 
451
        expredir(n->nredir.redirect);
 
452
        if (!backgnd && flags & EV_EXIT && !trap[0])
 
453
                goto nofork;
 
454
        INTOFF;
 
455
        jp = makejob(n, 1);
 
456
        if (forkshell(jp, n, backgnd) == 0) {
 
457
                INTON;
 
458
                flags |= EV_EXIT;
 
459
                if (backgnd)
 
460
                        flags &=~ EV_TESTED;
 
461
nofork:
 
462
                redirect(n->nredir.redirect, 0);
 
463
                evaltreenr(n->nredir.n, flags);
 
464
                /* never returns */
 
465
        }
 
466
        status = 0;
 
467
        if (! backgnd)
 
468
                status = waitforjob(jp);
 
469
        exitstatus = status;
 
470
        INTON;
 
471
}
 
472
 
 
473
 
 
474
 
 
475
/*
 
476
 * Compute the names of the files in a redirection list.
 
477
 */
 
478
 
 
479
STATIC void
 
480
expredir(union node *n)
 
481
{
 
482
        union node *redir;
 
483
 
 
484
        for (redir = n ; redir ; redir = redir->nfile.next) {
 
485
                struct arglist fn;
 
486
                fn.lastp = &fn.list;
 
487
                switch (redir->type) {
 
488
                case NFROMTO:
 
489
                case NFROM:
 
490
                case NTO:
 
491
                case NCLOBBER:
 
492
                case NAPPEND:
 
493
                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
 
494
                        redir->nfile.expfname = fn.list->text;
 
495
                        break;
 
496
                case NFROMFD:
 
497
                case NTOFD:
 
498
                        if (redir->ndup.vname) {
 
499
                                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
 
500
                                fixredir(redir, fn.list->text, 1);
 
501
                        }
 
502
                        break;
 
503
                }
 
504
        }
 
505
}
 
506
 
 
507
 
 
508
 
 
509
/*
 
510
 * Evaluate a pipeline.  All the processes in the pipeline are children
 
511
 * of the process creating the pipeline.  (This differs from some versions
 
512
 * of the shell, which make the last process in a pipeline the parent
 
513
 * of all the rest.)
 
514
 */
 
515
 
 
516
STATIC void
 
517
evalpipe(union node *n, int flags)
 
518
{
 
519
        struct job *jp;
 
520
        struct nodelist *lp;
 
521
        int pipelen;
 
522
        int prevfd;
 
523
        int pip[2];
 
524
 
 
525
        TRACE(("evalpipe(0x%lx) called\n", (long)n));
 
526
        pipelen = 0;
 
527
        for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
 
528
                pipelen++;
 
529
        flags |= EV_EXIT;
 
530
        INTOFF;
 
531
        jp = makejob(n, pipelen);
 
532
        prevfd = -1;
 
533
        for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
 
534
                prehash(lp->n);
 
535
                pip[1] = -1;
 
536
                if (lp->next) {
 
537
                        if (pipe(pip) < 0) {
 
538
                                close(prevfd);
 
539
                                sh_error("Pipe call failed");
 
540
                        }
 
541
                }
 
542
                if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
 
543
                        INTON;
 
544
                        if (pip[1] >= 0) {
 
545
                                close(pip[0]);
 
546
                        }
 
547
                        if (prevfd > 0) {
 
548
                                dup2(prevfd, 0);
 
549
                                close(prevfd);
 
550
                        }
 
551
                        if (pip[1] > 1) {
 
552
                                dup2(pip[1], 1);
 
553
                                close(pip[1]);
 
554
                        }
 
555
                        evaltreenr(lp->n, flags);
 
556
                        /* never returns */
 
557
                }
 
558
                if (prevfd >= 0)
 
559
                        close(prevfd);
 
560
                prevfd = pip[0];
 
561
                close(pip[1]);
 
562
        }
 
563
        if (n->npipe.backgnd == 0) {
 
564
                exitstatus = waitforjob(jp);
 
565
                TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
 
566
        }
 
567
        INTON;
 
568
}
 
569
 
 
570
 
 
571
 
 
572
/*
 
573
 * Execute a command inside back quotes.  If it's a builtin command, we
 
574
 * want to save its output in a block obtained from malloc.  Otherwise
 
575
 * we fork off a subprocess and get the output of the command via a pipe.
 
576
 * Should be called with interrupts off.
 
577
 */
 
578
 
 
579
void
 
580
evalbackcmd(union node *n, struct backcmd *result)
 
581
{
 
582
        int saveherefd;
 
583
 
 
584
        result->fd = -1;
 
585
        result->buf = NULL;
 
586
        result->nleft = 0;
 
587
        result->jp = NULL;
 
588
        if (n == NULL) {
 
589
                goto out;
 
590
        }
 
591
 
 
592
        saveherefd = herefd;
 
593
        herefd = -1;
 
594
 
 
595
#ifdef notyet
 
596
        /*
 
597
         * For now we disable executing builtins in the same
 
598
         * context as the shell, because we are not keeping
 
599
         * enough state to recover from changes that are
 
600
         * supposed only to affect subshells. eg. echo "`cd /`"
 
601
         */
 
602
        if (n->type == NCMD) {
 
603
                struct ifsregion saveifs;
 
604
                struct ifsregion *savelastp;
 
605
                struct nodelist *saveargbackq;
 
606
 
 
607
                saveifs = ifsfirst;
 
608
                savelastp = ifslastp;
 
609
                saveargbackq = argbackq;
 
610
 
 
611
                exitstatus = oexitstatus;
 
612
                evalcommand(n, EV_BACKCMD, result);
 
613
 
 
614
                ifsfirst = saveifs;
 
615
                ifslastp = savelastp;
 
616
                argbackq = saveargbackq;
 
617
        } else
 
618
#endif
 
619
        {
 
620
                int pip[2];
 
621
                struct job *jp;
 
622
 
 
623
                if (pipe(pip) < 0)
 
624
                        sh_error("Pipe call failed");
 
625
                jp = makejob(n, 1);
 
626
                if (forkshell(jp, n, FORK_NOJOB) == 0) {
 
627
                        FORCEINTON;
 
628
                        close(pip[0]);
 
629
                        if (pip[1] != 1) {
 
630
                                close(1);
 
631
                                copyfd(pip[1], 1);
 
632
                                close(pip[1]);
 
633
                        }
 
634
                        eflag = 0;
 
635
                        evaltreenr(n, EV_EXIT);
 
636
                        /* NOTREACHED */
 
637
                }
 
638
                close(pip[1]);
 
639
                result->fd = pip[0];
 
640
                result->jp = jp;
 
641
        }
 
642
        herefd = saveherefd;
 
643
out:
 
644
        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
 
645
                result->fd, result->buf, result->nleft, result->jp));
 
646
}
 
647
 
 
648
static char **
 
649
parse_command_args(char **argv, const char **path)
 
650
{
 
651
        char *cp, c;
 
652
 
 
653
        for (;;) {
 
654
                cp = *++argv;
 
655
                if (!cp)
 
656
                        return 0;
 
657
                if (*cp++ != '-')
 
658
                        break;
 
659
                if (!(c = *cp++))
 
660
                        break;
 
661
                if (c == '-' && !*cp) {
 
662
                        argv++;
 
663
                        break;
 
664
                }
 
665
                do {
 
666
                        switch (c) {
 
667
                        case 'p':
 
668
                                *path = defpath;
 
669
                                break;
 
670
                        default:
 
671
                                /* run 'typecmd' for other options */
 
672
                                return 0;
 
673
                        }
 
674
                } while ((c = *cp++));
 
675
        }
 
676
        return argv;
 
677
}
 
678
 
 
679
 
 
680
 
 
681
/*
 
682
 * Execute a simple command.
 
683
 */
 
684
 
 
685
STATIC void
 
686
#ifdef notyet
 
687
evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
 
688
#else
 
689
evalcommand(union node *cmd, int flags)
 
690
#endif
 
691
{
 
692
        struct stackmark smark;
 
693
        union node *argp;
 
694
        struct arglist arglist;
 
695
        struct arglist varlist;
 
696
        char **argv;
 
697
        int argc;
 
698
        struct strlist *sp;
 
699
#ifdef notyet
 
700
        int pip[2];
 
701
#endif
 
702
        struct cmdentry cmdentry;
 
703
        struct job *jp;
 
704
        char *lastarg;
 
705
        const char *path;
 
706
        int spclbltin;
 
707
        int execcmd;
 
708
        int status;
 
709
        char **nargv;
 
710
 
 
711
        /* First expand the arguments. */
 
712
        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
 
713
        setstackmark(&smark);
 
714
        back_exitstatus = 0;
 
715
 
 
716
        cmdentry.cmdtype = CMDBUILTIN;
 
717
        cmdentry.u.cmd = &bltin;
 
718
        varlist.lastp = &varlist.list;
 
719
        *varlist.lastp = NULL;
 
720
        arglist.lastp = &arglist.list;
 
721
        *arglist.lastp = NULL;
 
722
 
 
723
        argc = 0;
 
724
        for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
 
725
                struct strlist **spp;
 
726
 
 
727
                spp = arglist.lastp;
 
728
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
 
729
                for (sp = *spp; sp; sp = sp->next)
 
730
                        argc++;
 
731
        }
 
732
 
 
733
        argv = nargv = stalloc(sizeof (char *) * (argc + 1));
 
734
        for (sp = arglist.list ; sp ; sp = sp->next) {
 
735
                TRACE(("evalcommand arg: %s\n", sp->text));
 
736
                *nargv++ = sp->text;
 
737
        }
 
738
        *nargv = NULL;
 
739
 
 
740
        lastarg = NULL;
 
741
        if (iflag && funcnest == 0 && argc > 0)
 
742
                lastarg = nargv[-1];
 
743
 
 
744
        preverrout.fd = 2;
 
745
        expredir(cmd->ncmd.redirect);
 
746
        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
 
747
 
 
748
        path = vpath.text;
 
749
        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
 
750
                struct strlist **spp;
 
751
                char *p;
 
752
 
 
753
                spp = varlist.lastp;
 
754
                expandarg(argp, &varlist, EXP_VARTILDE);
 
755
 
 
756
                /*
 
757
                 * Modify the command lookup path, if a PATH= assignment
 
758
                 * is present
 
759
                 */
 
760
                p = (*spp)->text;
 
761
                if (varequal(p, path))
 
762
                        path = p;
 
763
        }
 
764
 
 
765
        /* Print the command if xflag is set. */
 
766
        if (xflag) {
 
767
                struct output *out;
 
768
                int sep;
 
769
 
 
770
                out = &preverrout;
 
771
                outstr(expandstr(ps4val()), out);
 
772
                sep = 0;
 
773
                sep = eprintlist(out, varlist.list, sep);
 
774
                eprintlist(out, arglist.list, sep);
 
775
                outcslow('\n', out);
 
776
#ifdef FLUSHERR
 
777
                flushout(out);
 
778
#endif
 
779
        }
 
780
 
 
781
        execcmd = 0;
 
782
        spclbltin = -1;
 
783
 
 
784
        /* Now locate the command. */
 
785
        if (argc) {
 
786
                const char *oldpath;
 
787
                int cmd_flag = DO_ERR;
 
788
 
 
789
                path += 5;
 
790
                oldpath = path;
 
791
                for (;;) {
 
792
                        find_command(argv[0], &cmdentry, cmd_flag, path);
 
793
                        if (cmdentry.cmdtype == CMDUNKNOWN) {
 
794
                                status = 127;
 
795
#ifdef FLUSHERR
 
796
                                flushout(&errout);
 
797
#endif
 
798
                                goto bail;
 
799
                        }
 
800
 
 
801
                        /* implement bltin and command here */
 
802
                        if (cmdentry.cmdtype != CMDBUILTIN)
 
803
                                break;
 
804
                        if (spclbltin < 0)
 
805
                                spclbltin = 
 
806
                                        cmdentry.u.cmd->flags &
 
807
                                        BUILTIN_SPECIAL
 
808
                                ;
 
809
                        if (cmdentry.u.cmd == EXECCMD)
 
810
                                execcmd++;
 
811
                        if (cmdentry.u.cmd != COMMANDCMD)
 
812
                                break;
 
813
 
 
814
                        path = oldpath;
 
815
                        nargv = parse_command_args(argv, &path);
 
816
                        if (!nargv)
 
817
                                break;
 
818
                        argc -= nargv - argv;
 
819
                        argv = nargv;
 
820
                        cmd_flag |= DO_NOFUNC;
 
821
                }
 
822
        }
 
823
 
 
824
        if (status) {
 
825
                /* We have a redirection error. */
 
826
                if (spclbltin > 0)
 
827
                        exraise(EXERROR);
 
828
bail:
 
829
                exitstatus = status;
 
830
                goto out;
 
831
        }
 
832
 
 
833
        /* Execute the command. */
 
834
        switch (cmdentry.cmdtype) {
 
835
        default:
 
836
                /* Fork off a child process if necessary. */
 
837
                if (!(flags & EV_EXIT) || trap[0]) {
 
838
                        INTOFF;
 
839
                        jp = makejob(cmd, 1);
 
840
                        if (forkshell(jp, cmd, FORK_FG) != 0) {
 
841
                                exitstatus = waitforjob(jp);
 
842
                                INTON;
 
843
                                break;
 
844
                        }
 
845
                        FORCEINTON;
 
846
                }
 
847
                listsetvar(varlist.list, VEXPORT|VSTACK);
 
848
                shellexec(argv, path, cmdentry.u.index);
 
849
                /* NOTREACHED */
 
850
 
 
851
        case CMDBUILTIN:
 
852
                cmdenviron = varlist.list;
 
853
                if (cmdenviron) {
 
854
                        struct strlist *list = cmdenviron;
 
855
                        int i = VNOSET;
 
856
                        if (spclbltin > 0 || argc == 0) {
 
857
                                i = 0;
 
858
                                if (execcmd && argc > 1)
 
859
                                        i = VEXPORT;
 
860
                        }
 
861
                        listsetvar(list, i);
 
862
                }
 
863
                if (evalbltin(cmdentry.u.cmd, argc, argv)) {
 
864
                        int status;
 
865
                        int i, j;
 
866
 
 
867
                        i = exception;
 
868
                        if (i == EXEXIT)
 
869
                                goto raise;
 
870
 
 
871
                        status = 2;
 
872
                        j = 0;
 
873
                        if (i == EXINT)
 
874
                                j = SIGINT;
 
875
                        if (i == EXSIG)
 
876
                                j = pendingsigs;
 
877
                        if (j)
 
878
                                status = j + 128;
 
879
                        exitstatus = status;
 
880
 
 
881
                        if (i == EXINT || spclbltin > 0) {
 
882
raise:
 
883
                                longjmp(handler->loc, 1);
 
884
                        }
 
885
                        FORCEINTON;
 
886
                }
 
887
                break;
 
888
 
 
889
        case CMDFUNCTION:
 
890
                listsetvar(varlist.list, 0);
 
891
                if (evalfun(cmdentry.u.func, argc, argv, flags))
 
892
                        goto raise;
 
893
                break;
 
894
        }
 
895
 
 
896
out:
 
897
        popredir(execcmd);
 
898
        if (lastarg)
 
899
                /* dsl: I think this is intended to be used to support
 
900
                 * '_' in 'vi' command mode during line editing...
 
901
                 * However I implemented that within libedit itself.
 
902
                 */
 
903
                setvar("_", lastarg, 0);
 
904
        popstackmark(&smark);
 
905
}
 
906
 
 
907
STATIC int
 
908
evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
 
909
        char *volatile savecmdname;
 
910
        struct jmploc *volatile savehandler;
 
911
        struct jmploc jmploc;
 
912
        int i;
 
913
 
 
914
        savecmdname = commandname;
 
915
        if ((i = setjmp(jmploc.loc)))
 
916
                goto cmddone;
 
917
        savehandler = handler;
 
918
        handler = &jmploc;
 
919
        commandname = argv[0];
 
920
        argptr = argv + 1;
 
921
        optptr = NULL;                  /* initialize nextopt */
 
922
        exitstatus = (*cmd->builtin)(argc, argv);
 
923
        flushall();
 
924
cmddone:
 
925
        exitstatus |= outerr(out1);
 
926
        freestdout();
 
927
        commandname = savecmdname;
 
928
        exsig = 0;
 
929
        handler = savehandler;
 
930
 
 
931
        return i;
 
932
}
 
933
 
 
934
STATIC int
 
935
evalfun(struct funcnode *func, int argc, char **argv, int flags)
 
936
{
 
937
        volatile struct shparam saveparam;
 
938
        struct localvar *volatile savelocalvars;
 
939
        struct jmploc *volatile savehandler;
 
940
        struct jmploc jmploc;
 
941
        int e;
 
942
 
 
943
        saveparam = shellparam;
 
944
        savelocalvars = localvars;
 
945
        if ((e = setjmp(jmploc.loc))) {
 
946
                goto funcdone;
 
947
        }
 
948
        INTOFF;
 
949
        savehandler = handler;
 
950
        handler = &jmploc;
 
951
        localvars = NULL;
 
952
        shellparam.malloc = 0;
 
953
        func->count++;
 
954
        funcnest++;
 
955
        INTON;
 
956
        shellparam.nparam = argc - 1;
 
957
        shellparam.p = argv + 1;
 
958
        shellparam.optind = 1;
 
959
        shellparam.optoff = -1;
 
960
        evaltree(&func->n, flags & EV_TESTED);
 
961
funcdone:
 
962
        INTOFF;
 
963
        funcnest--;
 
964
        freefunc(func);
 
965
        poplocalvars();
 
966
        localvars = savelocalvars;
 
967
        freeparam(&shellparam);
 
968
        shellparam = saveparam;
 
969
        handler = savehandler;
 
970
        INTON;
 
971
        evalskip &= ~SKIPFUNC;
 
972
        return e;
 
973
}
 
974
 
 
975
 
 
976
/*
 
977
 * Search for a command.  This is called before we fork so that the
 
978
 * location of the command will be available in the parent as well as
 
979
 * the child.  The check for "goodname" is an overly conservative
 
980
 * check that the name will not be subject to expansion.
 
981
 */
 
982
 
 
983
STATIC void
 
984
prehash(union node *n)
 
985
{
 
986
        struct cmdentry entry;
 
987
 
 
988
        if (n->type == NCMD && n->ncmd.args)
 
989
                if (goodname(n->ncmd.args->narg.text))
 
990
                        find_command(n->ncmd.args->narg.text, &entry, 0,
 
991
                                     pathval());
 
992
}
 
993
 
 
994
 
 
995
 
 
996
/*
 
997
 * Builtin commands.  Builtin commands whose functions are closely
 
998
 * tied to evaluation are implemented here.
 
999
 */
 
1000
 
 
1001
/*
 
1002
 * No command given.
 
1003
 */
 
1004
 
 
1005
STATIC int
 
1006
bltincmd(int argc, char **argv)
 
1007
{
 
1008
        /*
 
1009
         * Preserve exitstatus of a previous possible redirection
 
1010
         * as POSIX mandates
 
1011
         */
 
1012
        return back_exitstatus;
 
1013
}
 
1014
 
 
1015
 
 
1016
/*
 
1017
 * Handle break and continue commands.  Break, continue, and return are
 
1018
 * all handled by setting the evalskip flag.  The evaluation routines
 
1019
 * above all check this flag, and if it is set they start skipping
 
1020
 * commands rather than executing them.  The variable skipcount is
 
1021
 * the number of loops to break/continue, or the number of function
 
1022
 * levels to return.  (The latter is always 1.)  It should probably
 
1023
 * be an error to break out of more loops than exist, but it isn't
 
1024
 * in the standard shell so we don't make it one here.
 
1025
 */
 
1026
 
 
1027
int
 
1028
breakcmd(int argc, char **argv)
 
1029
{
 
1030
        int n = argc > 1 ? number(argv[1]) : 1;
 
1031
 
 
1032
        if (n <= 0)
 
1033
                sh_error(illnum, argv[1]);
 
1034
        if (n > loopnest)
 
1035
                n = loopnest;
 
1036
        if (n > 0) {
 
1037
                evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
 
1038
                skipcount = n;
 
1039
        }
 
1040
        return 0;
 
1041
}
 
1042
 
 
1043
 
 
1044
/*
 
1045
 * The return command.
 
1046
 */
 
1047
 
 
1048
int
 
1049
returncmd(int argc, char **argv)
 
1050
{
 
1051
        /*
 
1052
         * If called outside a function, do what ksh does;
 
1053
         * skip the rest of the file.
 
1054
         */
 
1055
        evalskip = funcnest ? SKIPFUNC : SKIPFILE;
 
1056
        return argv[1] ? number(argv[1]) : exitstatus;
 
1057
}
 
1058
 
 
1059
 
 
1060
int
 
1061
falsecmd(int argc, char **argv)
 
1062
{
 
1063
        return 1;
 
1064
}
 
1065
 
 
1066
 
 
1067
int
 
1068
truecmd(int argc, char **argv)
 
1069
{
 
1070
        return 0;
 
1071
}
 
1072
 
 
1073
 
 
1074
int
 
1075
execcmd(int argc, char **argv)
 
1076
{
 
1077
        if (argc > 1) {
 
1078
                iflag = 0;              /* exit on error */
 
1079
                mflag = 0;
 
1080
                optschanged();
 
1081
                shellexec(argv + 1, pathval(), 0);
 
1082
        }
 
1083
        return 0;
 
1084
}
 
1085
 
 
1086
 
 
1087
STATIC int
 
1088
eprintlist(struct output *out, struct strlist *sp, int sep)
 
1089
{
 
1090
        while (sp) {
 
1091
                const char *p;
 
1092
 
 
1093
                p = " %s" + (1 - sep);
 
1094
                sep |= 1;
 
1095
                outfmt(out, p, sp->text);
 
1096
                sp = sp->next;
 
1097
        }
 
1098
 
 
1099
        return sep;
 
1100
}