52a11bc48ae6ff4097591fa6d9b485ceb0f18646
[oweals/busybox.git] / shell / msh.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Minix shell port for busybox
4  *
5  * This version of the Minix shell was adapted for use in busybox
6  * by Erik Andersen <andersen@codepoet.org>
7  *
8  * - backtick expansion did not work properly
9  *   Jonas Holmberg <jonas.holmberg@axis.com>
10  *   Robert Schwebel <r.schwebel@pengutronix.de>
11  *   Erik Andersen <andersen@codepoet.org>
12  *
13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14  */
15
16 #include <sys/times.h>
17 #include <setjmp.h>
18
19 #ifdef STANDALONE
20 # ifndef _GNU_SOURCE
21 #  define _GNU_SOURCE
22 # endif
23 # include <sys/types.h>
24 # include <sys/stat.h>
25 # include <sys/wait.h>
26 # include <signal.h>
27 # include <stdio.h>
28 # include <stdlib.h>
29 # include <unistd.h>
30 # include <string.h>
31 # include <errno.h>
32 # include <dirent.h>
33 # include <fcntl.h>
34 # include <ctype.h>
35 # include <assert.h>
36 # define bb_dev_null "/dev/null"
37 # define DEFAULT_SHELL "/proc/self/exe"
38 # define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
39 # define bb_banner "busybox standalone"
40 # define ENABLE_FEATURE_SH_STANDALONE 0
41 # define bb_msg_memory_exhausted "memory exhausted"
42 # define xmalloc(size) malloc(size)
43 # define msh_main(argc,argv) main(argc,argv)
44 # define safe_read(fd,buf,count) read(fd,buf,count)
45 # define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
46 # define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
47 # define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
48 # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
49 static int find_applet_by_name(const char *applet)
50 {
51         return -1;
52 }
53 static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
54 {
55         unsigned i, out, res;
56         assert(sizeof(unsigned) == 4);
57         if (buflen) {
58                 out = 0;
59                 for (i = 1000000000; i; i /= 10) {
60                         res = n / i;
61                         if (res || out || i == 1) {
62                                 if (!--buflen) break;
63                                 out++;
64                                 n -= res*i;
65                                 *buf++ = '0' + res;
66                         }
67                 }
68         }
69         return buf;
70 }
71 static char *itoa_to_buf(int n, char *buf, unsigned buflen)
72 {
73         if (buflen && n < 0) {
74                 n = -n;
75                 *buf++ = '-';
76                 buflen--;
77         }
78         return utoa_to_buf((unsigned)n, buf, buflen);
79 }
80 static char local_buf[12];
81 static char *itoa(int n)
82 {
83         *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
84         return local_buf;
85 }
86 #else
87 # include "busybox.h" /* for applet_names */
88 #endif
89
90 //#define MSHDEBUG 4
91
92 #ifdef MSHDEBUG
93 static int mshdbg = MSHDEBUG;
94
95 #define DBGPRINTF(x)    if (mshdbg>0) printf x
96 #define DBGPRINTF0(x)   if (mshdbg>0) printf x
97 #define DBGPRINTF1(x)   if (mshdbg>1) printf x
98 #define DBGPRINTF2(x)   if (mshdbg>2) printf x
99 #define DBGPRINTF3(x)   if (mshdbg>3) printf x
100 #define DBGPRINTF4(x)   if (mshdbg>4) printf x
101 #define DBGPRINTF5(x)   if (mshdbg>5) printf x
102 #define DBGPRINTF6(x)   if (mshdbg>6) printf x
103 #define DBGPRINTF7(x)   if (mshdbg>7) printf x
104 #define DBGPRINTF8(x)   if (mshdbg>8) printf x
105 #define DBGPRINTF9(x)   if (mshdbg>9) printf x
106
107 static int mshdbg_rc = 0;
108
109 #define RCPRINTF(x)     if (mshdbg_rc) printf x
110
111 #else
112
113 #define DBGPRINTF(x)
114 #define DBGPRINTF0(x) ((void)0)
115 #define DBGPRINTF1(x) ((void)0)
116 #define DBGPRINTF2(x) ((void)0)
117 #define DBGPRINTF3(x) ((void)0)
118 #define DBGPRINTF4(x) ((void)0)
119 #define DBGPRINTF5(x) ((void)0)
120 #define DBGPRINTF6(x) ((void)0)
121 #define DBGPRINTF7(x) ((void)0)
122 #define DBGPRINTF8(x) ((void)0)
123 #define DBGPRINTF9(x) ((void)0)
124
125 #define RCPRINTF(x) ((void)0)
126
127 #endif                                                  /* MSHDEBUG */
128
129
130 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
131 # define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132 # define DEFAULT_USER_PROMPT "\\u:\\w$ "
133 #else
134 # define DEFAULT_ROOT_PROMPT "# "
135 # define DEFAULT_USER_PROMPT "$ "
136 #endif
137
138
139 /* -------- sh.h -------- */
140 /*
141  * shell
142  */
143
144 #define LINELIM   2100
145 #define NPUSH     8                             /* limit to input nesting */
146
147 #undef NOFILE
148 #define NOFILE    20                    /* Number of open files */
149 #define NUFILE    10                    /* Number of user-accessible files */
150 #define FDBASE    10                    /* First file usable by Shell */
151
152 /*
153  * values returned by wait
154  */
155 #define WAITSIG(s)  ((s) & 0177)
156 #define WAITVAL(s)  (((s) >> 8) & 0377)
157 #define WAITCORE(s) (((s) & 0200) != 0)
158
159 /*
160  * library and system definitions
161  */
162 typedef void xint;                      /* base type of jmp_buf, for not broken compilers */
163
164 /*
165  * shell components
166  */
167 #define NOBLOCK ((struct op *)NULL)
168 #define NOWORD  ((char *)NULL)
169 #define NOWORDS ((char **)NULL)
170 #define NOPIPE  ((int *)NULL)
171
172 /*
173  * redirection
174  */
175 struct ioword {
176         short io_unit;                  /* unit affected */
177         short io_flag;                  /* action (below) */
178         char *io_name;                  /* file name */
179 };
180
181 #define IOREAD   1                      /* < */
182 #define IOHERE   2                      /* << (here file) */
183 #define IOWRITE  4                      /* > */
184 #define IOCAT    8                      /* >> */
185 #define IOXHERE  16                     /* ${}, ` in << */
186 #define IODUP    32                     /* >&digit */
187 #define IOCLOSE  64                     /* >&- */
188
189 #define IODEFAULT (-1)                  /* token for default IO unit */
190
191
192 /*
193  * Description of a command or an operation on commands.
194  * Might eventually use a union.
195  */
196 struct op {
197         smallint type;                  /* operation type, see Txxxx below */
198         char **op_words;                /* arguments to a command */
199         struct ioword **ioact;          /* IO actions (eg, < > >>) */
200         struct op *left;
201         struct op *right;
202         char *str;                      /* identifier for case and for */
203 };
204
205 #define TCOM    1       /* command */
206 #define TPAREN  2       /* (c-list) */
207 #define TPIPE   3       /* a | b */
208 #define TLIST   4       /* a [&;] b */
209 #define TOR     5       /* || */
210 #define TAND    6       /* && */
211 #define TFOR    7
212 #define TDO     8
213 #define TCASE   9
214 #define TIF     10
215 #define TWHILE  11
216 #define TUNTIL  12
217 #define TELIF   13
218 #define TPAT    14      /* pattern in case */
219 #define TBRACE  15      /* {c-list} */
220 #define TASYNC  16      /* c & */
221 /* Added to support "." file expansion */
222 #define TDOT    17
223
224 /* Strings for names to make debug easier */
225 #ifdef MSHDEBUG
226 static const char *const T_CMD_NAMES[] = {
227         "PLACEHOLDER",
228         "TCOM",
229         "TPAREN",
230         "TPIPE",
231         "TLIST",
232         "TOR",
233         "TAND",
234         "TFOR",
235         "TDO",
236         "TCASE",
237         "TIF",
238         "TWHILE",
239         "TUNTIL",
240         "TELIF",
241         "TPAT",
242         "TBRACE",
243         "TASYNC",
244         "TDOT",
245 };
246 #endif
247
248 #define AREASIZE (90000)
249
250 /*
251  * flags to control evaluation of words
252  */
253 #define DOSUB    1      /* interpret $, `, and quotes */
254 #define DOBLANK  2      /* perform blank interpretation */
255 #define DOGLOB   4      /* interpret [?* */
256 #define DOKEY    8      /* move words with `=' to 2nd arg. list */
257 #define DOTRIM   16     /* trim resulting string */
258
259 #define DOALL    (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
260
261
262 struct brkcon {
263         jmp_buf brkpt;
264         struct brkcon *nextlev;
265 };
266
267
268 static smallint trapset;                        /* trap pending (signal number) */
269
270 static smallint yynerrs;                        /* yacc (flag) */
271
272 /* moved to G: static char line[LINELIM]; */
273
274 #if ENABLE_FEATURE_EDITING
275 static char *current_prompt;
276 static line_input_t *line_input_state;
277 #endif
278
279
280 /*
281  * other functions
282  */
283 static const char *rexecve(char *c, char **v, char **envp);
284 static char *evalstr(char *cp, int f);
285 static char *putn(int n);
286 static char *unquote(char *as);
287 static int rlookup(char *n);
288 static struct wdblock *glob(char *cp, struct wdblock *wb);
289 static int my_getc(int ec);
290 static int subgetc(char ec, int quoted);
291 static char **makenv(int all, struct wdblock *wb);
292 static char **eval(char **ap, int f);
293 static int setstatus(int s);
294 static int waitfor(int lastpid, int canintr);
295
296 static void onintr(int s);              /* SIGINT handler */
297
298 static int newenv(int f);
299 static void quitenv(void);
300 static void next(int f);
301 static void setdash(void);
302 static void onecommand(void);
303 static void runtrap(int i);
304
305
306 /* -------- area stuff -------- */
307
308 #define REGSIZE   sizeof(struct region)
309 #define GROWBY    (256)
310 /* #define SHRINKBY (64) */
311 #undef  SHRINKBY
312 #define FREE      (32767)
313 #define BUSY      (0)
314 #define ALIGN     (sizeof(int)-1)
315
316
317 struct region {
318         struct region *next;
319         int area;
320 };
321
322
323 /* -------- grammar stuff -------- */
324 typedef union {
325         char *cp;
326         char **wp;
327         int i;
328         struct op *o;
329 } YYSTYPE;
330
331 #define WORD    256
332 #define LOGAND  257
333 #define LOGOR   258
334 #define BREAK   259
335 #define IF      260
336 #define THEN    261
337 #define ELSE    262
338 #define ELIF    263
339 #define FI      264
340 #define CASE    265
341 #define ESAC    266
342 #define FOR     267
343 #define WHILE   268
344 #define UNTIL   269
345 #define DO      270
346 #define DONE    271
347 #define IN      272
348 /* Added for "." file expansion */
349 #define DOT     273
350
351 #define YYERRCODE 300
352
353 /* flags to yylex */
354 #define CONTIN 01     /* skip new lines to complete command */
355
356 static struct op *pipeline(int cf);
357 static struct op *andor(void);
358 static struct op *c_list(void);
359 static int synio(int cf);
360 static void musthave(int c, int cf);
361 static struct op *simple(void);
362 static struct op *nested(int type, int mark);
363 static struct op *command(int cf);
364 static struct op *dogroup(int onlydone);
365 static struct op *thenpart(void);
366 static struct op *elsepart(void);
367 static struct op *caselist(void);
368 static struct op *casepart(void);
369 static char **pattern(void);
370 static char **wordlist(void);
371 static struct op *list(struct op *t1, struct op *t2);
372 static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
373 static struct op *newtp(void);
374 static struct op *namelist(struct op *t);
375 static char **copyw(void);
376 static void word(char *cp);
377 static struct ioword **copyio(void);
378 static struct ioword *io(int u, int f, char *cp);
379 static int yylex(int cf);
380 static int collect(int c, int c1);
381 static int dual(int c);
382 static void diag(int ec);
383 static char *tree(unsigned size);
384
385 /* -------- var.h -------- */
386
387 struct var {
388         char *value;
389         char *name;
390         struct var *next;
391         char status;
392 };
393
394 #define COPYV   1                               /* flag to setval, suggesting copy */
395 #define RONLY   01                              /* variable is read-only */
396 #define EXPORT  02                              /* variable is to be exported */
397 #define GETCELL 04                              /* name & value space was got with getcell */
398
399 static int yyparse(void);
400
401
402 /* -------- io.h -------- */
403 /* io buffer */
404 struct iobuf {
405         unsigned id;            /* buffer id */
406         char buf[512];          /* buffer */
407         char *bufp;             /* pointer into buffer */
408         char *ebufp;            /* pointer to end of buffer */
409 };
410
411 /* possible arguments to an IO function */
412 struct ioarg {
413         const char *aword;
414         char **awordlist;
415         int afile;              /* file descriptor */
416         unsigned afid;          /* buffer id */
417         off_t afpos;            /* file position */
418         struct iobuf *afbuf;    /* buffer for this file */
419 };
420
421 /* an input generator's state */
422 struct io {
423         int (*iofn) (struct ioarg *, struct io *);
424         struct ioarg *argp;
425         int peekc;
426         char prev;              /* previous character read by readc() */
427         char nlcount;           /* for `'s */
428         char xchar;             /* for `'s */
429         char task;              /* reason for pushed IO */
430 };
431 /* ->task: */
432 #define XOTHER  0       /* none of the below */
433 #define XDOLL   1       /* expanding ${} */
434 #define XGRAVE  2       /* expanding `'s */
435 #define XIO     3       /* file IO */
436
437
438 /*
439  * input generators for IO structure
440  */
441 static int nlchar(struct ioarg *ap);
442 static int strchar(struct ioarg *ap);
443 static int qstrchar(struct ioarg *ap);
444 static int filechar(struct ioarg *ap);
445 static int herechar(struct ioarg *ap);
446 static int linechar(struct ioarg *ap);
447 static int gravechar(struct ioarg *ap, struct io *iop);
448 static int qgravechar(struct ioarg *ap, struct io *iop);
449 static int dolchar(struct ioarg *ap);
450 static int wdchar(struct ioarg *ap);
451 static void scraphere(void);
452 static void freehere(int area);
453 static void gethere(void);
454 static void markhere(char *s, struct ioword *iop);
455 static int herein(char *hname, int xdoll);
456 static int run(struct ioarg *argp, int (*f) (struct ioarg *));
457
458
459 static int eofc(void);
460 static int readc(void);
461 static void unget(int c);
462 static void ioecho(char c);
463
464
465 /*
466  * IO control
467  */
468 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
469 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
470 static int remap(int fd);
471 static int openpipe(int *pv);
472 static void closepipe(int *pv);
473 static struct io *setbase(struct io *ip);
474
475 /* -------- word.h -------- */
476
477 #define NSTART  16                              /* default number of words to allow for initially */
478
479 struct wdblock {
480         short w_bsize;
481         short w_nword;
482         /* bounds are arbitrary */
483         char *w_words[1];
484 };
485
486 static struct wdblock *addword(char *wd, struct wdblock *wb);
487 static struct wdblock *newword(int nw);
488 static char **getwords(struct wdblock *wb);
489
490 /* -------- misc stuff -------- */
491
492 static int dolabel(struct op *t, char **args);
493 static int dohelp(struct op *t, char **args);
494 static int dochdir(struct op *t, char **args);
495 static int doshift(struct op *t, char **args);
496 static int dologin(struct op *t, char **args);
497 static int doumask(struct op *t, char **args);
498 static int doexec(struct op *t, char **args);
499 static int dodot(struct op *t, char **args);
500 static int dowait(struct op *t, char **args);
501 static int doread(struct op *t, char **args);
502 static int doeval(struct op *t, char **args);
503 static int dotrap(struct op *t, char **args);
504 static int dobreak(struct op *t, char **args);
505 static int doexit(struct op *t, char **args);
506 static int doexport(struct op *t, char **args);
507 static int doreadonly(struct op *t, char **args);
508 static int doset(struct op *t, char **args);
509 static int dotimes(struct op *t, char **args);
510 static int docontinue(struct op *t, char **args);
511
512 static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
513 static int execute(struct op *t, int *pin, int *pout, int no_fork);
514 static int iosetup(struct ioword *iop, int pipein, int pipeout);
515 static void brkset(struct brkcon *bc);
516 static int getsig(char *s);
517 static void setsig(int n, sighandler_t f);
518 static int getn(char *as);
519 static int brkcontin(char *cp, int val);
520 static void rdexp(char **wp, void (*f) (struct var *), int key);
521 static void badid(char *s);
522 static void varput(char *s, int out);
523 static int expand(const char *cp, struct wdblock **wbp, int f);
524 static char *blank(int f);
525 static int dollar(int quoted);
526 static int grave(int quoted);
527 static void globname(char *we, char *pp);
528 static char *generate(char *start1, char *end1, char *middle, char *end);
529 static int anyspcl(struct wdblock *wb);
530 static void readhere(char **name, char *s, int ec);
531 static int xxchar(struct ioarg *ap);
532
533 struct here {
534         char *h_tag;
535         char h_dosub;
536         struct ioword *h_iop;
537         struct here *h_next;
538 };
539
540 static const char *const signame[] = {
541         "Signal 0",
542         "Hangup",
543         NULL,  /* interrupt */
544         "Quit",
545         "Illegal instruction",
546         "Trace/BPT trap",
547         "Abort",
548         "Bus error",
549         "Floating Point Exception",
550         "Killed",
551         "SIGUSR1",
552         "SIGSEGV",
553         "SIGUSR2",
554         NULL,  /* broken pipe */
555         "Alarm clock",
556         "Terminated"
557 };
558
559
560 typedef int (*builtin_func_ptr)(struct op *, char **);
561
562 struct builtincmd {
563         const char *name;
564         builtin_func_ptr builtinfunc;
565 };
566
567 static const struct builtincmd builtincmds[] = {
568         { "."       , dodot      },
569         { ":"       , dolabel    },
570         { "break"   , dobreak    },
571         { "cd"      , dochdir    },
572         { "continue", docontinue },
573         { "eval"    , doeval     },
574         { "exec"    , doexec     },
575         { "exit"    , doexit     },
576         { "export"  , doexport   },
577         { "help"    , dohelp     },
578         { "login"   , dologin    },
579         { "newgrp"  , dologin    },
580         { "read"    , doread     },
581         { "readonly", doreadonly },
582         { "set"     , doset      },
583         { "shift"   , doshift    },
584         { "times"   , dotimes    },
585         { "trap"    , dotrap     },
586         { "umask"   , doumask    },
587         { "wait"    , dowait     },
588         { NULL      , NULL       },
589 };
590
591 static struct op *scantree(struct op *);
592 static struct op *dowholefile(int, int);
593
594
595 /* Globals */
596 static char **dolv;
597 static int dolc;
598 static int exstat;
599 static smallint gflg;                   /* (seems to be a parse error indicator) */
600 static smallint interactive;            /* Is this an interactive shell */
601 static smallint execflg;
602 static smallint isbreak;                /* "break" statement was seen */
603 static int multiline;                   /* '\n' changed to ';' (counter) */
604 static struct op *outtree;              /* result from parser */
605 static xint *failpt;
606 static xint *errpt;
607 static struct brkcon *brklist;
608 static struct wdblock *wdlist;
609 static struct wdblock *iolist;
610
611 #ifdef MSHDEBUG
612 static struct var *mshdbg_var;
613 #endif
614 static struct var *vlist;               /* dictionary */
615 static struct var *homedir;             /* home directory */
616 static struct var *prompt;              /* main prompt */
617 static struct var *cprompt;             /* continuation prompt */
618 static struct var *path;                /* search path for commands */
619 static struct var *shell;               /* shell to interpret command files */
620 static struct var *ifs;                 /* field separators */
621
622 static int areanum;                     /* current allocation area */
623 static smallint intr;                   /* interrupt pending (bool) */
624 static smallint heedint = 1;            /* heed interrupt signals (bool) */
625 static int inparse;
626 static char *null = (char*)"";          /* null value for variable */
627 static void (*qflag)(int) = SIG_IGN;
628 static int startl;
629 static int peeksym;
630 static int nlseen;
631 static int iounit = IODEFAULT;
632 static YYSTYPE yylval;
633 static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
634
635 static struct here *inhere;     /* list of hear docs while parsing */
636 static struct here *acthere;    /* list of active here documents */
637 static struct region *areabot;  /* bottom of area */
638 static struct region *areatop;  /* top of area */
639 static struct region *areanxt;  /* starting point of scan */
640 static void *brktop;
641 static void *brkaddr;
642
643 #define AFID_NOBUF      (~0)
644 #define AFID_ID         0
645
646
647 /*
648  * parsing & execution environment
649  */
650 struct env {
651         char *linep;
652         struct io *iobase;
653         struct io *iop;
654         xint *errpt;            /* void * */
655         int iofd;
656         struct env *oenv;
657 };
658
659
660 struct globals {
661         struct env global_env;
662         struct ioarg temparg; // = { .afid = AFID_NOBUF };      /* temporary for PUSHIO */
663         unsigned bufid; // = AFID_ID;   /* buffer id counter */
664         char ourtrap[_NSIG + 1];
665         char *trap[_NSIG + 1];
666         struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
667         struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
668         struct ioarg ioargstack[NPUSH];
669         /*
670          * flags:
671          * -e: quit on error
672          * -k: look for name=value everywhere on command line
673          * -n: no execution
674          * -t: exit after reading and executing one command
675          * -v: echo as read
676          * -x: trace
677          * -u: unset variables net diagnostic
678          */
679         char flags['z' - 'a' + 1];
680         char filechar_cmdbuf[BUFSIZ];
681         char line[LINELIM];
682         char child_cmd[LINELIM];
683
684         struct io iostack[NPUSH];
685
686         char grave__var_name[LINELIM];
687         char grave__alt_value[LINELIM];
688 };
689
690 #define G (*ptr_to_globals)
691 #define global_env      (G.global_env     )
692 #define temparg         (G.temparg        )
693 #define bufid           (G.bufid          )
694 #define ourtrap         (G.ourtrap        )
695 #define trap            (G.trap           )
696 #define sharedbuf       (G.sharedbuf      )
697 #define mainbuf         (G.mainbuf        )
698 #define ioargstack      (G.ioargstack     )
699 /* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
700 #define FLAG            (G.flags - 'a'    )
701 #define filechar_cmdbuf (G.filechar_cmdbuf)
702 #define line            (G.line           )
703 #define child_cmd       (G.child_cmd      )
704 #define iostack         (G.iostack        )
705 #define INIT_G() do { \
706         SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
707         global_env.linep = line; \
708         global_env.iobase = iostack; \
709         global_env.iop = iostack - 1; \
710         global_env.iofd = FDBASE; \
711         temparg.afid = AFID_NOBUF; \
712         bufid = AFID_ID; \
713 } while (0)
714
715
716 /* in substitution */
717 #define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
718
719 #define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
720
721 #ifdef MSHDEBUG
722 static void print_tree(struct op *head)
723 {
724         if (head == NULL) {
725                 DBGPRINTF(("PRINT_TREE: no tree\n"));
726                 return;
727         }
728
729         DBGPRINTF(("NODE: %p,  left %p, right %p\n", head, head->left,
730                            head->right));
731
732         if (head->left)
733                 print_tree(head->left);
734
735         if (head->right)
736                 print_tree(head->right);
737 }
738 #endif /* MSHDEBUG */
739
740
741 /*
742  * IO functions
743  */
744 static void prs(const char *s)
745 {
746         if (*s)
747                 write(2, s, strlen(s));
748 }
749
750 static void prn(unsigned u)
751 {
752         prs(itoa(u));
753 }
754
755 static void echo(char **wp)
756 {
757         int i;
758
759         prs("+");
760         for (i = 0; wp[i]; i++) {
761                 if (i)
762                         prs(" ");
763                 prs(wp[i]);
764         }
765         prs("\n");
766 }
767
768 static void closef(int i)
769 {
770         if (i > 2)
771                 close(i);
772 }
773
774 static void closeall(void)
775 {
776         int u;
777
778         for (u = NUFILE; u < NOFILE;)
779                 close(u++);
780 }
781
782
783 /* fail but return to process next command */
784 static void fail(void) ATTRIBUTE_NORETURN;
785 static void fail(void)
786 {
787         longjmp(failpt, 1);
788         /* NOTREACHED */
789 }
790
791 /* abort shell (or fail in subshell) */
792 static void leave(void) ATTRIBUTE_NORETURN;
793 static void leave(void)
794 {
795         DBGPRINTF(("LEAVE: leave called!\n"));
796
797         if (execflg)
798                 fail();
799         scraphere();
800         freehere(1);
801         runtrap(0);
802         _exit(exstat);
803         /* NOTREACHED */
804 }
805
806 static void warn(const char *s)
807 {
808         if (*s) {
809                 prs(s);
810                 exstat = -1;
811         }
812         prs("\n");
813         if (FLAG['e'])
814                 leave();
815 }
816
817 static void err(const char *s)
818 {
819         warn(s);
820         if (FLAG['n'])
821                 return;
822         if (!interactive)
823                 leave();
824         if (global_env.errpt)
825                 longjmp(global_env.errpt, 1);
826         closeall();
827         global_env.iop = global_env.iobase = iostack;
828 }
829
830
831 /* -------- area.c -------- */
832
833 /*
834  * All memory between (char *)areabot and (char *)(areatop+1) is
835  * exclusively administered by the area management routines.
836  * It is assumed that sbrk() and brk() manipulate the high end.
837  */
838
839 #define sbrk(X) ({ \
840         void * __q = (void *)-1; \
841         if (brkaddr + (int)(X) < brktop) { \
842                 __q = brkaddr; \
843                 brkaddr += (int)(X); \
844         } \
845         __q; \
846 })
847
848 static void initarea(void)
849 {
850         brkaddr = xmalloc(AREASIZE);
851         brktop = brkaddr + AREASIZE;
852
853         while ((long) sbrk(0) & ALIGN)
854                 sbrk(1);
855         areabot = (struct region *) sbrk(REGSIZE);
856
857         areabot->next = areabot;
858         areabot->area = BUSY;
859         areatop = areabot;
860         areanxt = areabot;
861 }
862
863 static char *getcell(unsigned nbytes)
864 {
865         int nregio;
866         struct region *p, *q;
867         int i;
868
869         if (nbytes == 0) {
870                 puts("getcell(0)");
871                 abort();
872         }
873         /* silly and defeats the algorithm */
874         /*
875          * round upwards and add administration area
876          */
877         nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
878         p = areanxt;
879         for (;;) {
880                 if (p->area > areanum) {
881                         /*
882                          * merge free cells
883                          */
884                         while ((q = p->next)->area > areanum && q != areanxt)
885                                 p->next = q->next;
886                         /*
887                          * exit loop if cell big enough
888                          */
889                         if (q >= p + nregio)
890                                 goto found;
891                 }
892                 p = p->next;
893                 if (p == areanxt)
894                         break;
895         }
896         i = nregio >= GROWBY ? nregio : GROWBY;
897         p = (struct region *) sbrk(i * REGSIZE);
898         if (p == (struct region *) -1)
899                 return NULL;
900         p--;
901         if (p != areatop) {
902                 puts("not contig");
903                 abort();                                /* allocated areas are contiguous */
904         }
905         q = p + i;
906         p->next = q;
907         p->area = FREE;
908         q->next = areabot;
909         q->area = BUSY;
910         areatop = q;
911  found:
912         /*
913          * we found a FREE area big enough, pointed to by 'p', and up to 'q'
914          */
915         areanxt = p + nregio;
916         if (areanxt < q) {
917                 /*
918                  * split into requested area and rest
919                  */
920                 if (areanxt + 1 > q) {
921                         puts("OOM");
922                         abort();                        /* insufficient space left for admin */
923                 }
924                 areanxt->next = q;
925                 areanxt->area = FREE;
926                 p->next = areanxt;
927         }
928         p->area = areanum;
929         return (char *) (p + 1);
930 }
931
932 static void freecell(char *cp)
933 {
934         struct region *p;
935
936         p = (struct region *) cp;
937         if (p != NULL) {
938                 p--;
939                 if (p < areanxt)
940                         areanxt = p;
941                 p->area = FREE;
942         }
943 }
944 #define DELETE(obj) freecell((char *)obj)
945
946 static void freearea(int a)
947 {
948         struct region *p, *top;
949
950         top = areatop;
951         for (p = areabot; p != top; p = p->next)
952                 if (p->area >= a)
953                         p->area = FREE;
954 }
955
956 static void setarea(char *cp, int a)
957 {
958         struct region *p;
959
960         p = (struct region *) cp;
961         if (p != NULL)
962                 (p - 1)->area = a;
963 }
964
965 static int getarea(char *cp)
966 {
967         return ((struct region *) cp - 1)->area;
968 }
969
970 static void garbage(void)
971 {
972         struct region *p, *q, *top;
973
974         top = areatop;
975         for (p = areabot; p != top; p = p->next) {
976                 if (p->area > areanum) {
977                         while ((q = p->next)->area > areanum)
978                                 p->next = q->next;
979                         areanxt = p;
980                 }
981         }
982 #ifdef SHRINKBY
983         if (areatop >= q + SHRINKBY && q->area > areanum) {
984                 brk((char *) (q + 1));
985                 q->next = areabot;
986                 q->area = BUSY;
987                 areatop = q;
988         }
989 #endif
990 }
991
992 static void *get_space(int n)
993 {
994         char *cp;
995
996         cp = getcell(n);
997         if (cp == NULL)
998                 err("out of string space");
999         return cp;
1000 }
1001
1002 static char *strsave(const char *s, int a)
1003 {
1004         char *cp;
1005
1006         cp = get_space(strlen(s) + 1);
1007         if (cp == NULL) {
1008 // FIXME: I highly doubt this is good.
1009                 return (char*)"";
1010         }
1011         setarea(cp, a);
1012         strcpy(cp, s);
1013         return cp;
1014 }
1015
1016
1017 /* -------- var.c -------- */
1018
1019 static int eqname(const char *n1, const char *n2)
1020 {
1021         for (; *n1 != '=' && *n1 != '\0'; n1++)
1022                 if (*n2++ != *n1)
1023                         return 0;
1024         return *n2 == '\0' || *n2 == '=';
1025 }
1026
1027 static const char *findeq(const char *cp)
1028 {
1029         while (*cp != '\0' && *cp != '=')
1030                 cp++;
1031         return cp;
1032 }
1033
1034 /*
1035  * Find the given name in the dictionary
1036  * and return its value.  If the name was
1037  * not previously there, enter it now and
1038  * return a null value.
1039  */
1040 static struct var *lookup(const char *n)
1041 {
1042 // FIXME: dirty hack
1043         static struct var dummy;
1044
1045         struct var *vp;
1046         const char *cp;
1047         char *xp;
1048         int c;
1049
1050         if (isdigit(*n)) {
1051                 dummy.name = (char*)n;
1052                 for (c = 0; isdigit(*n) && c < 1000; n++)
1053                         c = c * 10 + *n - '0';
1054                 dummy.status = RONLY;
1055                 dummy.value = (c <= dolc ? dolv[c] : null);
1056                 return &dummy;
1057         }
1058
1059         for (vp = vlist; vp; vp = vp->next)
1060                 if (eqname(vp->name, n))
1061                         return vp;
1062
1063         cp = findeq(n);
1064         vp = get_space(sizeof(*vp));
1065         if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
1066                 dummy.name = dummy.value = (char*)"";
1067                 return &dummy;
1068         }
1069
1070         xp = vp->name;
1071         while ((*xp = *n++) != '\0' && *xp != '=')
1072                 xp++;
1073         *xp++ = '=';
1074         *xp = '\0';
1075         setarea((char *) vp, 0);
1076         setarea((char *) vp->name, 0);
1077         vp->value = null;
1078         vp->next = vlist;
1079         vp->status = GETCELL;
1080         vlist = vp;
1081         return vp;
1082 }
1083
1084 /*
1085  * if name is not NULL, it must be
1086  * a prefix of the space `val',
1087  * and end with `='.
1088  * this is all so that exporting
1089  * values is reasonably painless.
1090  */
1091 static void nameval(struct var *vp, const char *val, const char *name)
1092 {
1093         const char *cp;
1094         char *xp;
1095         int fl;
1096
1097         if (vp->status & RONLY) {
1098                 xp = vp->name;
1099                 while (*xp && *xp != '=')
1100                         fputc(*xp++, stderr);
1101                 err(" is read-only");
1102                 return;
1103         }
1104         fl = 0;
1105         if (name == NULL) {
1106                 xp = get_space(strlen(vp->name) + strlen(val) + 2);
1107                 if (xp == NULL)
1108                         return;
1109                 /* make string: name=value */
1110                 setarea(xp, 0);
1111                 name = xp;
1112                 cp = vp->name;
1113                 while ((*xp = *cp++) != '\0' && *xp != '=')
1114                         xp++;
1115                 *xp++ = '=';
1116                 strcpy(xp, val);
1117                 val = xp;
1118                 fl = GETCELL;
1119         }
1120         if (vp->status & GETCELL)
1121                 freecell(vp->name);             /* form new string `name=value' */
1122         vp->name = (char*)name;
1123         vp->value = (char*)val;
1124         vp->status |= fl;
1125 }
1126
1127 /*
1128  * give variable at `vp' the value `val'.
1129  */
1130 static void setval(struct var *vp, const char *val)
1131 {
1132         nameval(vp, val, NULL);
1133 }
1134
1135 static void export(struct var *vp)
1136 {
1137         vp->status |= EXPORT;
1138 }
1139
1140 static void ronly(struct var *vp)
1141 {
1142         if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1143                 vp->status |= RONLY;
1144 }
1145
1146 static int isassign(const char *s)
1147 {
1148         unsigned char c;
1149         DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1150
1151         c = *s;
1152         /* no isalpha() - we shouldn't use locale */
1153         /* c | 0x20 - lowercase (Latin) letters */
1154         if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1155                 /* not letter */
1156                 return 0;
1157
1158         while (1) {
1159                 c = *++s;
1160                 if (c == '=')
1161                         return 1;
1162                 if (c == '\0')
1163                         return 0;
1164                 if (c != '_'
1165                  && (unsigned)(c - '0') > 9  /* not number */
1166                  && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
1167                 ) {
1168                         return 0;
1169                 }
1170         }
1171 }
1172
1173 static int assign(const char *s, int cf)
1174 {
1175         const char *cp;
1176         struct var *vp;
1177
1178         DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1179
1180         if (!isalpha(*s) && *s != '_')
1181                 return 0;
1182         for (cp = s; *cp != '='; cp++)
1183                 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1184                         return 0;
1185         vp = lookup(s);
1186         nameval(vp, ++cp, cf == COPYV ? NULL : s);
1187         if (cf != COPYV)
1188                 vp->status &= ~GETCELL;
1189         return 1;
1190 }
1191
1192 static int checkname(char *cp)
1193 {
1194         DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1195
1196         if (!isalpha(*cp++) && *(cp - 1) != '_')
1197                 return 0;
1198         while (*cp)
1199                 if (!isalnum(*cp++) && *(cp - 1) != '_')
1200                         return 0;
1201         return 1;
1202 }
1203
1204 static void putvlist(int f, int out)
1205 {
1206         struct var *vp;
1207
1208         for (vp = vlist; vp; vp = vp->next) {
1209                 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1210                         if (vp->status & EXPORT)
1211                                 write(out, "export ", 7);
1212                         if (vp->status & RONLY)
1213                                 write(out, "readonly ", 9);
1214                         write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1215                         write(out, "\n", 1);
1216                 }
1217         }
1218 }
1219
1220
1221 /*
1222  * trap handling
1223  */
1224 static void sig(int i)
1225 {
1226         trapset = i;
1227         signal(i, sig);
1228 }
1229
1230 static void runtrap(int i)
1231 {
1232         char *trapstr;
1233
1234         trapstr = trap[i];
1235         if (trapstr == NULL)
1236                 return;
1237
1238         if (i == 0)
1239                 trap[i] = NULL;
1240
1241         RUN(aword, trapstr, nlchar);
1242 }
1243
1244
1245 static void setdash(void)
1246 {
1247         char *cp;
1248         int c;
1249         char m['z' - 'a' + 1];
1250
1251         cp = m;
1252         for (c = 'a'; c <= 'z'; c++)
1253                 if (FLAG[c])
1254                         *cp++ = c;
1255         *cp = '\0';
1256         setval(lookup("-"), m);
1257 }
1258
1259 static int newfile(char *s)
1260 {
1261         int f;
1262
1263         DBGPRINTF7(("NEWFILE: opening %s\n", s));
1264
1265         f = 0;
1266         if (NOT_LONE_DASH(s)) {
1267                 DBGPRINTF(("NEWFILE: s is %s\n", s));
1268                 f = open(s, O_RDONLY);
1269                 if (f < 0) {
1270                         prs(s);
1271                         err(": cannot open");
1272                         return 1;
1273                 }
1274         }
1275
1276         next(remap(f));
1277         return 0;
1278 }
1279
1280
1281 struct op *scantree(struct op *head)
1282 {
1283         struct op *dotnode;
1284
1285         if (head == NULL)
1286                 return NULL;
1287
1288         if (head->left != NULL) {
1289                 dotnode = scantree(head->left);
1290                 if (dotnode)
1291                         return dotnode;
1292         }
1293
1294         if (head->right != NULL) {
1295                 dotnode = scantree(head->right);
1296                 if (dotnode)
1297                         return dotnode;
1298         }
1299
1300         if (head->op_words == NULL)
1301                 return NULL;
1302
1303         DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1304
1305         if ((head->type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
1306                 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1307                 return head;
1308         }
1309
1310         return NULL;
1311 }
1312
1313
1314 static void onecommand(void)
1315 {
1316         int i;
1317         jmp_buf m1;
1318
1319         DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
1320
1321         while (global_env.oenv)
1322                 quitenv();
1323
1324         areanum = 1;
1325         freehere(areanum);
1326         freearea(areanum);
1327         garbage();
1328         wdlist = 0;
1329         iolist = 0;
1330         global_env.errpt = 0;
1331         global_env.linep = line;
1332         yynerrs = 0;
1333         multiline = 0;
1334         inparse = 1;
1335         intr = 0;
1336         execflg = 0;
1337
1338         failpt = m1;
1339         setjmp(failpt);         /* Bruce Evans' fix */
1340         failpt = m1;
1341         if (setjmp(failpt) || yyparse() || intr) {
1342                 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1343
1344                 while (global_env.oenv)
1345                         quitenv();
1346                 scraphere();
1347                 if (!interactive && intr)
1348                         leave();
1349                 inparse = 0;
1350                 intr = 0;
1351                 return;
1352         }
1353
1354         inparse = 0;
1355         brklist = 0;
1356         intr = 0;
1357         execflg = 0;
1358
1359         if (!FLAG['n']) {
1360                 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1361                                    outtree));
1362                 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
1363         }
1364
1365         if (!interactive && intr) {
1366                 execflg = 0;
1367                 leave();
1368         }
1369
1370         i = trapset;
1371         if (i != 0) {
1372                 trapset = 0;
1373                 runtrap(i);
1374         }
1375 }
1376
1377 static int newenv(int f)
1378 {
1379         struct env *ep;
1380
1381         DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1382
1383         if (f) {
1384                 quitenv();
1385                 return 1;
1386         }
1387
1388         ep = get_space(sizeof(*ep));
1389         if (ep == NULL) {
1390                 while (global_env.oenv)
1391                         quitenv();
1392                 fail();
1393         }
1394         *ep = global_env;
1395         global_env.oenv = ep;
1396         global_env.errpt = errpt;
1397
1398         return 0;
1399 }
1400
1401 static void quitenv(void)
1402 {
1403         struct env *ep;
1404         int fd;
1405
1406         DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
1407
1408         ep = global_env.oenv;
1409         if (ep != NULL) {
1410                 fd = global_env.iofd;
1411                 global_env = *ep;
1412                 /* should close `'d files */
1413                 DELETE(ep);
1414                 while (--fd >= global_env.iofd)
1415                         close(fd);
1416         }
1417 }
1418
1419 /*
1420  * Is character c in s?
1421  */
1422 static int any(int c, const char *s)
1423 {
1424         while (*s)
1425                 if (*s++ == c)
1426                         return 1;
1427         return 0;
1428 }
1429
1430 /*
1431  * Is any character from s1 in s2?
1432  */
1433 static int anys(const char *s1, const char *s2)
1434 {
1435         while (*s1)
1436                 if (any(*s1++, s2))
1437                         return 1;
1438         return 0;
1439 }
1440
1441 static char *putn(int n)
1442 {
1443         return itoa(n);
1444 }
1445
1446 static void next(int f)
1447 {
1448         PUSHIO(afile, f, filechar);
1449 }
1450
1451 static void onintr(int s)                                       /* ANSI C requires a parameter */
1452 {
1453         signal(SIGINT, onintr);
1454         intr = 1;
1455         if (interactive) {
1456                 if (inparse) {
1457                         prs("\n");
1458                         fail();
1459                 }
1460         } else if (heedint) {
1461                 execflg = 0;
1462                 leave();
1463         }
1464 }
1465
1466
1467 /* -------- gmatch.c -------- */
1468 /*
1469  * int gmatch(string, pattern)
1470  * char *string, *pattern;
1471  *
1472  * Match a pattern as in sh(1).
1473  */
1474
1475 #define CMASK   0377
1476 #define QUOTE   0200
1477 #define QMASK   (CMASK & ~QUOTE)
1478 #define NOT     '!'                                     /* might use ^ */
1479
1480 static const char *cclass(const char *p, int sub)
1481 {
1482         int c, d, not, found;
1483
1484         not = (*p == NOT);
1485         if (not != 0)
1486                 p++;
1487         found = not;
1488         do {
1489                 if (*p == '\0')
1490                         return NULL;
1491                 c = *p & CMASK;
1492                 if (p[1] == '-' && p[2] != ']') {
1493                         d = p[2] & CMASK;
1494                         p++;
1495                 } else
1496                         d = c;
1497                 if (c == sub || (c <= sub && sub <= d))
1498                         found = !not;
1499         } while (*++p != ']');
1500         return found ? p + 1 : NULL;
1501 }
1502
1503 static int gmatch(const char *s, const char *p)
1504 {
1505         int sc, pc;
1506
1507         if (s == NULL || p == NULL)
1508                 return 0;
1509
1510         while ((pc = *p++ & CMASK) != '\0') {
1511                 sc = *s++ & QMASK;
1512                 switch (pc) {
1513                 case '[':
1514                         p = cclass(p, sc);
1515                         if (p == NULL)
1516                                 return 0;
1517                         break;
1518
1519                 case '?':
1520                         if (sc == 0)
1521                                 return 0;
1522                         break;
1523
1524                 case '*':
1525                         s--;
1526                         do {
1527                                 if (*p == '\0' || gmatch(s, p))
1528                                         return 1;
1529                         } while (*s++ != '\0');
1530                         return 0;
1531
1532                 default:
1533                         if (sc != (pc & ~QUOTE))
1534                                 return 0;
1535                 }
1536         }
1537         return *s == '\0';
1538 }
1539
1540
1541 /* -------- csyn.c -------- */
1542 /*
1543  * shell: syntax (C version)
1544  */
1545
1546 static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1547 static void yyerror(const char *s)
1548 {
1549         yynerrs = 1;
1550         if (interactive && global_env.iop <= iostack) {
1551                 multiline = 0;
1552                 while (eofc() == 0 && yylex(0) != '\n')
1553                         continue;
1554         }
1555         err(s);
1556         fail();
1557 }
1558
1559 static void zzerr(void) ATTRIBUTE_NORETURN;
1560 static void zzerr(void)
1561 {
1562         yyerror("syntax error");
1563 }
1564
1565 int yyparse(void)
1566 {
1567         DBGPRINTF7(("YYPARSE: enter...\n"));
1568
1569         startl = 1;
1570         peeksym = 0;
1571         yynerrs = 0;
1572         outtree = c_list();
1573         musthave('\n', 0);
1574         return yynerrs; /* 0/1 */
1575 }
1576
1577 static struct op *pipeline(int cf)
1578 {
1579         struct op *t, *p;
1580         int c;
1581
1582         DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1583
1584         t = command(cf);
1585
1586         DBGPRINTF9(("PIPELINE: t=%p\n", t));
1587
1588         if (t != NULL) {
1589                 while ((c = yylex(0)) == '|') {
1590                         p = command(CONTIN);
1591                         if (p == NULL) {
1592                                 DBGPRINTF8(("PIPELINE: error!\n"));
1593                                 zzerr();
1594                         }
1595
1596                         if (t->type != TPAREN && t->type != TCOM) {
1597                                 /* shell statement */
1598                                 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1599                         }
1600
1601                         t = block(TPIPE, t, p, NOWORDS);
1602                 }
1603                 peeksym = c;
1604         }
1605
1606         DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
1607         return t;
1608 }
1609
1610 static struct op *andor(void)
1611 {
1612         struct op *t, *p;
1613         int c;
1614
1615         DBGPRINTF7(("ANDOR: enter...\n"));
1616
1617         t = pipeline(0);
1618
1619         DBGPRINTF9(("ANDOR: t=%p\n", t));
1620
1621         if (t != NULL) {
1622                 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1623                         p = pipeline(CONTIN);
1624                         if (p == NULL) {
1625                                 DBGPRINTF8(("ANDOR: error!\n"));
1626                                 zzerr();
1627                         }
1628
1629                         t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1630                 }                                               /* WHILE */
1631
1632                 peeksym = c;
1633         }
1634
1635         DBGPRINTF7(("ANDOR: returning t=%p\n", t));
1636         return t;
1637 }
1638
1639 static struct op *c_list(void)
1640 {
1641         struct op *t, *p;
1642         int c;
1643
1644         DBGPRINTF7(("C_LIST: enter...\n"));
1645
1646         t = andor();
1647
1648         if (t != NULL) {
1649                 peeksym = yylex(0);
1650                 if (peeksym == '&')
1651                         t = block(TASYNC, t, NOBLOCK, NOWORDS);
1652
1653                 while ((c = yylex(0)) == ';' || c == '&'
1654                  || (multiline && c == '\n')
1655                 ) {
1656                         p = andor();
1657                         if (p== NULL)
1658                                 return t;
1659
1660                         peeksym = yylex(0);
1661                         if (peeksym == '&')
1662                                 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1663
1664                         t = list(t, p);
1665                 }                                               /* WHILE */
1666
1667                 peeksym = c;
1668         }
1669         /* IF */
1670         DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1671         return t;
1672 }
1673
1674 static int synio(int cf)
1675 {
1676         struct ioword *iop;
1677         int i;
1678         int c;
1679
1680         DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1681
1682         c = yylex(cf);
1683         if (c != '<' && c != '>') {
1684                 peeksym = c;
1685                 return 0;
1686         }
1687
1688         i = yylval.i;
1689         musthave(WORD, 0);
1690         iop = io(iounit, i, yylval.cp);
1691         iounit = IODEFAULT;
1692
1693         if (i & IOHERE)
1694                 markhere(yylval.cp, iop);
1695
1696         DBGPRINTF7(("SYNIO: returning 1\n"));
1697         return 1;
1698 }
1699
1700 static void musthave(int c, int cf)
1701 {
1702         peeksym = yylex(cf);
1703         if (peeksym != c) {
1704                 DBGPRINTF7(("MUSTHAVE: error!\n"));
1705                 zzerr();
1706         }
1707
1708         peeksym = 0;
1709 }
1710
1711 static struct op *simple(void)
1712 {
1713         struct op *t;
1714
1715         t = NULL;
1716         for (;;) {
1717                 switch (peeksym = yylex(0)) {
1718                 case '<':
1719                 case '>':
1720                         (void) synio(0);
1721                         break;
1722
1723                 case WORD:
1724                         if (t == NULL) {
1725                                 t = newtp();
1726                                 t->type = TCOM;
1727                         }
1728                         peeksym = 0;
1729                         word(yylval.cp);
1730                         break;
1731
1732                 default:
1733                         return t;
1734                 }
1735         }
1736 }
1737
1738 static struct op *nested(int type, int mark)
1739 {
1740         struct op *t;
1741
1742         DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1743
1744         multiline++;
1745         t = c_list();
1746         musthave(mark, 0);
1747         multiline--;
1748         return block(type, t, NOBLOCK, NOWORDS);
1749 }
1750
1751 static struct op *command(int cf)
1752 {
1753         struct op *t;
1754         struct wdblock *iosave;
1755         int c;
1756
1757         DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1758
1759         iosave = iolist;
1760         iolist = NULL;
1761
1762         if (multiline)
1763                 cf |= CONTIN;
1764
1765         while (synio(cf))
1766                 cf = 0;
1767
1768         c = yylex(cf);
1769
1770         switch (c) {
1771         default:
1772                 peeksym = c;
1773                 t = simple();
1774                 if (t == NULL) {
1775                         if (iolist == NULL)
1776                                 return NULL;
1777                         t = newtp();
1778                         t->type = TCOM;
1779                 }
1780                 break;
1781
1782         case '(':
1783                 t = nested(TPAREN, ')');
1784                 break;
1785
1786         case '{':
1787                 t = nested(TBRACE, '}');
1788                 break;
1789
1790         case FOR:
1791                 t = newtp();
1792                 t->type = TFOR;
1793                 musthave(WORD, 0);
1794                 startl = 1;
1795                 t->str = yylval.cp;
1796                 multiline++;
1797                 t->op_words = wordlist();
1798                 c = yylex(0);
1799                 if (c != '\n' && c != ';')
1800                         peeksym = c;
1801                 t->left = dogroup(0);
1802                 multiline--;
1803                 break;
1804
1805         case WHILE:
1806         case UNTIL:
1807                 multiline++;
1808                 t = newtp();
1809                 t->type = (c == WHILE ? TWHILE : TUNTIL);
1810                 t->left = c_list();
1811                 t->right = dogroup(1);
1812                 /* t->op_words = NULL; - newtp() did this */
1813                 multiline--;
1814                 break;
1815
1816         case CASE:
1817                 t = newtp();
1818                 t->type = TCASE;
1819                 musthave(WORD, 0);
1820                 t->str = yylval.cp;
1821                 startl++;
1822                 multiline++;
1823                 musthave(IN, CONTIN);
1824                 startl++;
1825
1826                 t->left = caselist();
1827
1828                 musthave(ESAC, 0);
1829                 multiline--;
1830                 break;
1831
1832         case IF:
1833                 multiline++;
1834                 t = newtp();
1835                 t->type = TIF;
1836                 t->left = c_list();
1837                 t->right = thenpart();
1838                 musthave(FI, 0);
1839                 multiline--;
1840                 break;
1841
1842         case DOT:
1843                 t = newtp();
1844                 t->type = TDOT;
1845
1846                 musthave(WORD, 0);              /* gets name of file */
1847                 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1848
1849                 word(yylval.cp);                /* add word to wdlist */
1850                 word(NOWORD);                   /* terminate  wdlist */
1851                 t->op_words = copyw();          /* dup wdlist */
1852                 break;
1853
1854         }
1855
1856         while (synio(0))
1857                 continue;
1858
1859         t = namelist(t);
1860         iolist = iosave;
1861
1862         DBGPRINTF(("COMMAND: returning %p\n", t));
1863
1864         return t;
1865 }
1866
1867 static struct op *dowholefile(int type, int mark)
1868 {
1869         struct op *t;
1870
1871         DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1872
1873         multiline++;
1874         t = c_list();
1875         multiline--;
1876         t = block(type, t, NOBLOCK, NOWORDS);
1877         DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
1878         return t;
1879 }
1880
1881 static struct op *dogroup(int onlydone)
1882 {
1883         int c;
1884         struct op *mylist;
1885
1886         c = yylex(CONTIN);
1887         if (c == DONE && onlydone)
1888                 return NULL;
1889         if (c != DO)
1890                 zzerr();
1891         mylist = c_list();
1892         musthave(DONE, 0);
1893         return mylist;
1894 }
1895
1896 static struct op *thenpart(void)
1897 {
1898         int c;
1899         struct op *t;
1900
1901         c = yylex(0);
1902         if (c != THEN) {
1903                 peeksym = c;
1904                 return NULL;
1905         }
1906         t = newtp();
1907         /*t->type = 0; - newtp() did this */
1908         t->left = c_list();
1909         if (t->left == NULL)
1910                 zzerr();
1911         t->right = elsepart();
1912         return t;
1913 }
1914
1915 static struct op *elsepart(void)
1916 {
1917         int c;
1918         struct op *t;
1919
1920         switch (c = yylex(0)) {
1921         case ELSE:
1922                 t = c_list();
1923                 if (t == NULL)
1924                         zzerr();
1925                 return t;
1926
1927         case ELIF:
1928                 t = newtp();
1929                 t->type = TELIF;
1930                 t->left = c_list();
1931                 t->right = thenpart();
1932                 return t;
1933
1934         default:
1935                 peeksym = c;
1936                 return NULL;
1937         }
1938 }
1939
1940 static struct op *caselist(void)
1941 {
1942         struct op *t;
1943
1944         t = NULL;
1945         while ((peeksym = yylex(CONTIN)) != ESAC) {
1946                 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
1947                 t = list(t, casepart());
1948         }
1949
1950         DBGPRINTF(("CASELIST, returning t=%p\n", t));
1951         return t;
1952 }
1953
1954 static struct op *casepart(void)
1955 {
1956         struct op *t;
1957
1958         DBGPRINTF7(("CASEPART: enter...\n"));
1959
1960         t = newtp();
1961         t->type = TPAT;
1962         t->op_words = pattern();
1963         musthave(')', 0);
1964         t->left = c_list();
1965         peeksym = yylex(CONTIN);
1966         if (peeksym != ESAC)
1967                 musthave(BREAK, CONTIN);
1968
1969         DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
1970
1971         return t;
1972 }
1973
1974 static char **pattern(void)
1975 {
1976         int c, cf;
1977
1978         cf = CONTIN;
1979         do {
1980                 musthave(WORD, cf);
1981                 word(yylval.cp);
1982                 cf = 0;
1983                 c = yylex(0);
1984         } while (c == '|');
1985         peeksym = c;
1986         word(NOWORD);
1987
1988         return copyw();
1989 }
1990
1991 static char **wordlist(void)
1992 {
1993         int c;
1994
1995         c = yylex(0);
1996         if (c != IN) {
1997                 peeksym = c;
1998                 return NULL;
1999         }
2000         startl = 0;
2001         while ((c = yylex(0)) == WORD)
2002                 word(yylval.cp);
2003         word(NOWORD);
2004         peeksym = c;
2005         return copyw();
2006 }
2007
2008 /*
2009  * supporting functions
2010  */
2011 static struct op *list(struct op *t1, struct op *t2)
2012 {
2013         DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
2014
2015         if (t1 == NULL)
2016                 return t2;
2017         if (t2 == NULL)
2018                 return t1;
2019
2020         return block(TLIST, t1, t2, NOWORDS);
2021 }
2022
2023 static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
2024 {
2025         struct op *t;
2026
2027         DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2028
2029         t = newtp();
2030         t->type = type;
2031         t->left = t1;
2032         t->right = t2;
2033         t->op_words = wp;
2034
2035         DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
2036
2037         return t;
2038 }
2039
2040 /* See if given string is a shell multiline (FOR, IF, etc) */
2041 static int rlookup(char *n)
2042 {
2043         struct res {
2044                 char r_name[6];
2045                 int16_t r_val;
2046         };
2047         static const struct res restab[] = {
2048                 { "for"  , FOR    },
2049                 { "case" , CASE   },
2050                 { "esac" , ESAC   },
2051                 { "while", WHILE  },
2052                 { "do"   , DO     },
2053                 { "done" , DONE   },
2054                 { "if"   , IF     },
2055                 { "in"   , IN     },
2056                 { "then" , THEN   },
2057                 { "else" , ELSE   },
2058                 { "elif" , ELIF   },
2059                 { "until", UNTIL  },
2060                 { "fi"   , FI     },
2061                 { ";;"   , BREAK  },
2062                 { "||"   , LOGOR  },
2063                 { "&&"   , LOGAND },
2064                 { "{"    , '{'    },
2065                 { "}"    , '}'    },
2066                 { "."    , DOT    },
2067                 { },
2068         };
2069
2070         const struct res *rp;
2071
2072         DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2073
2074         for (rp = restab; rp->r_name[0]; rp++)
2075                 if (strcmp(rp->r_name, n) == 0) {
2076                         DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2077                         return rp->r_val;       /* Return numeric code for shell multiline */
2078                 }
2079
2080         DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2081         return 0;                                       /* Not a shell multiline */
2082 }
2083
2084 static struct op *newtp(void)
2085 {
2086         struct op *t;
2087
2088         t = (struct op *) tree(sizeof(*t));
2089         memset(t, 0, sizeof(*t));
2090
2091         DBGPRINTF3(("NEWTP: allocated %p\n", t));
2092
2093         return t;
2094 }
2095
2096 static struct op *namelist(struct op *t)
2097 {
2098         DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
2099                                 T_CMD_NAMES[t->type], iolist));
2100
2101         if (iolist) {
2102                 iolist = addword((char *) NULL, iolist);
2103                 t->ioact = copyio();
2104         } else
2105                 t->ioact = NULL;
2106
2107         if (t->type != TCOM) {
2108                 if (t->type != TPAREN && t->ioact != NULL) {
2109                         t = block(TPAREN, t, NOBLOCK, NOWORDS);
2110                         t->ioact = t->left->ioact;
2111                         t->left->ioact = NULL;
2112                 }
2113                 return t;
2114         }
2115
2116         word(NOWORD);
2117         t->op_words = copyw();
2118
2119         return t;
2120 }
2121
2122 static char **copyw(void)
2123 {
2124         char **wd;
2125
2126         wd = getwords(wdlist);
2127         wdlist = 0;
2128         return wd;
2129 }
2130
2131 static void word(char *cp)
2132 {
2133         wdlist = addword(cp, wdlist);
2134 }
2135
2136 static struct ioword **copyio(void)
2137 {
2138         struct ioword **iop;
2139
2140         iop = (struct ioword **) getwords(iolist);
2141         iolist = 0;
2142         return iop;
2143 }
2144
2145 static struct ioword *io(int u, int f, char *cp)
2146 {
2147         struct ioword *iop;
2148
2149         iop = (struct ioword *) tree(sizeof(*iop));
2150         iop->io_unit = u;
2151         iop->io_flag = f;
2152         iop->io_name = cp;
2153         iolist = addword((char *) iop, iolist);
2154         return iop;
2155 }
2156
2157 static int yylex(int cf)
2158 {
2159         int c, c1;
2160         int atstart;
2161
2162         c = peeksym;
2163         if (c > 0) {
2164                 peeksym = 0;
2165                 if (c == '\n')
2166                         startl = 1;
2167                 return c;
2168         }
2169
2170         nlseen = 0;
2171         atstart = startl;
2172         startl = 0;
2173         yylval.i = 0;
2174         global_env.linep = line;
2175
2176 /* MALAMO */
2177         line[LINELIM - 1] = '\0';
2178
2179  loop:
2180         while ((c = my_getc(0)) == ' ' || c == '\t')    /* Skip whitespace */
2181                 continue;
2182
2183         switch (c) {
2184         default:
2185                 if (any(c, "0123456789")) {
2186                         c1 = my_getc(0);
2187                         unget(c1);
2188                         if (c1 == '<' || c1 == '>') {
2189                                 iounit = c - '0';
2190                                 goto loop;
2191                         }
2192                         *global_env.linep++ = c;
2193                         c = c1;
2194                 }
2195                 break;
2196
2197         case '#':                                       /* Comment, skip to next newline or End-of-string */
2198                 while ((c = my_getc(0)) != '\0' && c != '\n')
2199                         continue;
2200                 unget(c);
2201                 goto loop;
2202
2203         case 0:
2204                 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2205                 return c;
2206
2207         case '$':
2208                 DBGPRINTF9(("YYLEX: found $\n"));
2209                 *global_env.linep++ = c;
2210                 c = my_getc(0);
2211                 if (c == '{') {
2212                         c = collect(c, '}');
2213                         if (c != '\0')
2214                                 return c;
2215                         goto pack;
2216                 }
2217                 break;
2218
2219         case '`':
2220         case '\'':
2221         case '"':
2222                 c = collect(c, c);
2223                 if (c != '\0')
2224                         return c;
2225                 goto pack;
2226
2227         case '|':
2228         case '&':
2229         case ';':
2230                 startl = 1;
2231                 /* If more chars process them, else return NULL char */
2232                 c1 = dual(c);
2233                 if (c1 != '\0')
2234                         return c1;
2235                 return c;
2236
2237         case '^':
2238                 startl = 1;
2239                 return '|';
2240         case '>':
2241         case '<':
2242                 diag(c);
2243                 return c;
2244
2245         case '\n':
2246                 nlseen++;
2247                 gethere();
2248                 startl = 1;
2249                 if (multiline || cf & CONTIN) {
2250                         if (interactive && global_env.iop <= iostack) {
2251 #if ENABLE_FEATURE_EDITING
2252                                 current_prompt = cprompt->value;
2253 #else
2254                                 prs(cprompt->value);
2255 #endif
2256                         }
2257                         if (cf & CONTIN)
2258                                 goto loop;
2259                 }
2260                 return c;
2261
2262         case '(':
2263         case ')':
2264                 startl = 1;
2265                 return c;
2266         }
2267
2268         unget(c);
2269
2270  pack:
2271         while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
2272                 if (global_env.linep >= elinep)
2273                         err("word too long");
2274                 else
2275                         *global_env.linep++ = c;
2276         };
2277
2278         unget(c);
2279
2280         if (any(c, "\"'`$"))
2281                 goto loop;
2282
2283         *global_env.linep++ = '\0';
2284
2285         if (atstart) {
2286                 c = rlookup(line);
2287                 if (c != 0) {
2288                         startl = 1;
2289                         return c;
2290                 }
2291         }
2292
2293         yylval.cp = strsave(line, areanum);
2294         return WORD;
2295 }
2296
2297
2298 static int collect(int c, int c1)
2299 {
2300         char s[2];
2301
2302         DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2303
2304         *global_env.linep++ = c;
2305         while ((c = my_getc(c1)) != c1) {
2306                 if (c == 0) {
2307                         unget(c);
2308                         s[0] = c1;
2309                         s[1] = 0;
2310                         prs("no closing ");
2311                         yyerror(s);
2312                         return YYERRCODE;
2313                 }
2314                 if (interactive && c == '\n' && global_env.iop <= iostack) {
2315 #if ENABLE_FEATURE_EDITING
2316                         current_prompt = cprompt->value;
2317 #else
2318                         prs(cprompt->value);
2319 #endif
2320                 }
2321                 *global_env.linep++ = c;
2322         }
2323
2324         *global_env.linep++ = c;
2325
2326         DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2327
2328         return 0;
2329 }
2330
2331 /* "multiline commands" helper func */
2332 /* see if next 2 chars form a shell multiline */
2333 static int dual(int c)
2334 {
2335         char s[3];
2336         char *cp = s;
2337
2338         DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2339
2340         *cp++ = c;              /* c is the given "peek" char */
2341         *cp++ = my_getc(0);     /* get next char of input */
2342         *cp = '\0';             /* add EOS marker */
2343
2344         c = rlookup(s);         /* see if 2 chars form a shell multiline */
2345         if (c == 0)
2346                 unget(*--cp);   /* String is not a shell multiline, put peek char back */
2347
2348         return c;               /* String is multiline, return numeric multiline (restab) code */
2349 }
2350
2351 static void diag(int ec)
2352 {
2353         int c;
2354
2355         DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2356
2357         c = my_getc(0);
2358         if (c == '>' || c == '<') {
2359                 if (c != ec)
2360                         zzerr();
2361                 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
2362                 c = my_getc(0);
2363         } else
2364                 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
2365         if (c != '&' || yylval.i == IOHERE)
2366                 unget(c);
2367         else
2368                 yylval.i |= IODUP;
2369 }
2370
2371 static char *tree(unsigned size)
2372 {
2373         char *t;
2374
2375         t = getcell(size);
2376         if (t == NULL) {
2377                 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2378                 prs("command line too complicated\n");
2379                 fail();
2380                 /* NOTREACHED */
2381         }
2382         return t;
2383 }
2384
2385
2386 /* VARARGS1 */
2387 /* ARGSUSED */
2388
2389 /* -------- exec.c -------- */
2390
2391 static struct op **find1case(struct op *t, const char *w)
2392 {
2393         struct op *t1;
2394         struct op **tp;
2395         char **wp;
2396         char *cp;
2397
2398         if (t == NULL) {
2399                 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2400                 return NULL;
2401         }
2402
2403         DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2404                                 T_CMD_NAMES[t->type]));
2405
2406         if (t->type == TLIST) {
2407                 tp = find1case(t->left, w);
2408                 if (tp != NULL) {
2409                         DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2410                         return tp;
2411                 }
2412                 t1 = t->right;                  /* TPAT */
2413         } else
2414                 t1 = t;
2415
2416         for (wp = t1->op_words; *wp;) {
2417                 cp = evalstr(*wp++, DOSUB);
2418                 if (cp && gmatch(w, cp)) {
2419                         DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2420                                                 &t1->left));
2421                         return &t1->left;
2422                 }
2423         }
2424
2425         DBGPRINTF(("FIND1CASE: returning NULL\n"));
2426         return NULL;
2427 }
2428
2429 static struct op *findcase(struct op *t, const char *w)
2430 {
2431         struct op **tp;
2432
2433         tp = find1case(t, w);
2434         return tp != NULL ? *tp : NULL;
2435 }
2436
2437 /*
2438  * execute tree
2439  */
2440
2441 static int execute(struct op *t, int *pin, int *pout, int no_fork)
2442 {
2443         struct op *t1;
2444         volatile int i, rv, a;
2445         const char *cp;
2446         char **wp, **wp2;
2447         struct var *vp;
2448         struct op *outtree_save;
2449         struct brkcon bc;
2450
2451 #if __GNUC__
2452         /* Avoid longjmp clobbering */
2453         (void) &wp;
2454 #endif
2455
2456         if (t == NULL) {
2457                 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2458                 return 0;
2459         }
2460
2461         DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->op_words is %s\n", t,
2462                            t->type, T_CMD_NAMES[t->type],
2463                            ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
2464
2465         rv = 0;
2466         a = areanum++;
2467         wp2 = t->op_words;
2468         wp = (wp2 != NULL)
2469                 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2470                 : NULL;
2471
2472         switch (t->type) {
2473         case TDOT:
2474                 DBGPRINTF3(("EXECUTE: TDOT\n"));
2475
2476                 outtree_save = outtree;
2477
2478                 newfile(evalstr(t->op_words[0], DOALL));
2479
2480                 t->left = dowholefile(TLIST, 0);
2481                 t->right = NULL;
2482
2483                 outtree = outtree_save;
2484
2485                 if (t->left)
2486                         rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2487                 if (t->right)
2488                         rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2489                 break;
2490
2491         case TPAREN:
2492                 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2493                 break;
2494
2495         case TCOM:
2496                 rv = forkexec(t, pin, pout, no_fork, wp);
2497                 break;
2498
2499         case TPIPE:
2500                 {
2501                         int pv[2];
2502
2503                         rv = openpipe(pv);
2504                         if (rv < 0)
2505                                 break;
2506                         pv[0] = remap(pv[0]);
2507                         pv[1] = remap(pv[1]);
2508                         (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2509                         rv = execute(t->right, pv, pout, /* no_fork: */ 0);
2510                 }
2511                 break;
2512
2513         case TLIST:
2514                 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2515                 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2516                 break;
2517
2518         case TASYNC:
2519                 {
2520                         smallint hinteractive = interactive;
2521
2522                         DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2523
2524                         i = vfork();
2525                         if (i == 0) { /* child */
2526                                 signal(SIGINT, SIG_IGN);
2527                                 signal(SIGQUIT, SIG_IGN);
2528                                 if (interactive)
2529                                         signal(SIGTERM, SIG_DFL);
2530                                 interactive = 0;
2531                                 if (pin == NULL) {
2532                                         close(0);
2533                                         xopen(bb_dev_null, O_RDONLY);
2534                                 }
2535                                 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
2536                         }
2537                         interactive = hinteractive;
2538                         if (i != -1) {
2539                                 setval(lookup("!"), putn(i));
2540                                 closepipe(pin);
2541                                 if (interactive) {
2542                                         prs(putn(i));
2543                                         prs("\n");
2544                                 }
2545                         } else
2546                                 rv = -1;
2547                         setstatus(rv);
2548                 }
2549                 break;
2550
2551         case TOR:
2552         case TAND:
2553                 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2554                 t1 = t->right;
2555                 if (t1 != NULL && (rv == 0) == (t->type == TAND))
2556                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2557                 break;
2558
2559         case TFOR:
2560                 if (wp == NULL) {
2561                         wp = dolv + 1;
2562                         i = dolc;
2563                         if (i < 0)
2564                                 i = 0;
2565                 } else {
2566                         i = -1;
2567                         while (*wp++ != NULL)
2568                                 continue;
2569                 }
2570                 vp = lookup(t->str);
2571                 while (setjmp(bc.brkpt))
2572                         if (isbreak)
2573                                 goto broken;
2574                 brkset(&bc);
2575                 for (t1 = t->left; i-- && *wp != NULL;) {
2576                         setval(vp, *wp++);
2577                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2578                 }
2579                 brklist = brklist->nextlev;
2580                 break;
2581
2582         case TWHILE:
2583         case TUNTIL:
2584                 while (setjmp(bc.brkpt))
2585                         if (isbreak)
2586                                 goto broken;
2587                 brkset(&bc);
2588                 t1 = t->left;
2589                 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
2590                         rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2591                 brklist = brklist->nextlev;
2592                 break;
2593
2594         case TIF:
2595         case TELIF:
2596                 if (t->right != NULL) {
2597                         rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2598                                 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2599                                 execute(t->right->right, pin, pout, /* no_fork: */ 0);
2600                 }
2601                 break;
2602
2603         case TCASE:
2604                 cp = evalstr(t->str, DOSUB | DOTRIM);
2605                 if (cp == NULL)
2606                         cp = "";
2607
2608                 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2609                                         ((t->str == NULL) ? "NULL" : t->str),
2610                                         ((cp == NULL) ? "NULL" : cp)));
2611
2612                 t1 = findcase(t->left, cp);
2613                 if (t1 != NULL) {
2614                         DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2615                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2616                         DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2617                 }
2618                 break;
2619
2620         case TBRACE:
2621 /*
2622                 iopp = t->ioact;
2623                 if (i)
2624                         while (*iopp)
2625                                 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2626                                         rv = -1;
2627                                         break;
2628                                 }
2629 */
2630                 if (rv >= 0) {
2631                         t1 = t->left;
2632                         if (t1) {
2633                                 rv = execute(t1, pin, pout, /* no_fork: */ 0);
2634                         }
2635                 }
2636                 break;
2637
2638         };
2639
2640  broken:
2641 // Restoring op_words is most likely not needed now: see comment in forkexec()
2642 // (also take a look at exec builtin (doexec) - it touches t->op_words)
2643         t->op_words = wp2;
2644         isbreak = 0;
2645         freehere(areanum);
2646         freearea(areanum);
2647         areanum = a;
2648         if (interactive && intr) {
2649                 closeall();
2650                 fail();
2651         }
2652
2653         i = trapset;
2654         if (i != 0) {
2655                 trapset = 0;
2656                 runtrap(i);
2657         }
2658
2659         DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2660         return rv;
2661 }
2662
2663 static builtin_func_ptr inbuilt(const char *s)
2664 {
2665         const struct builtincmd *bp;
2666
2667         for (bp = builtincmds; bp->name; bp++)
2668                 if (strcmp(bp->name, s) == 0)
2669                         return bp->builtinfunc;
2670         return NULL;
2671 }
2672
2673 static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
2674 {
2675         pid_t newpid;
2676         int i;
2677         builtin_func_ptr bltin = NULL;
2678         const char *bltin_name = NULL;
2679         const char *cp;
2680         struct ioword **iopp;
2681         int resetsig;
2682         char **owp;
2683         int forked;
2684
2685         int *hpin = pin;
2686         int *hpout = pout;
2687         char *hwp;
2688         smallint hinteractive;
2689         smallint hintr;
2690         smallint hexecflg;
2691         struct brkcon *hbrklist;
2692
2693 #if __GNUC__
2694         /* Avoid longjmp clobbering */
2695         (void) &pin;
2696         (void) &pout;
2697         (void) &wp;
2698         (void) &bltin;
2699         (void) &cp;
2700         (void) &resetsig;
2701         (void) &owp;
2702 #endif
2703
2704         DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2705                         pout, no_fork));
2706         DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2707                         ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
2708         owp = wp;
2709         resetsig = 0;
2710         if (t->type == TCOM) {
2711                 while (*wp++ != NULL)
2712                         continue;
2713                 cp = *wp;
2714
2715                 /* strip all initial assignments */
2716                 /* FIXME: not correct wrt PATH=yyy command etc */
2717                 if (FLAG['x']) {
2718                         DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2719                                                 cp, wp, owp));
2720                         echo(cp ? wp : owp);
2721                 }
2722
2723                 if (cp == NULL) {
2724                         if (t->ioact == NULL) {
2725                                 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2726                                         continue;
2727                                 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2728                                 return setstatus(0);
2729                         }
2730                 } else { /* cp != NULL */
2731                         bltin_name = cp;
2732                         bltin = inbuilt(cp);
2733                 }
2734         }
2735
2736         forked = 0;
2737         // We were pointing t->op_words to temporary (expanded) arg list:
2738         // t->op_words = wp;
2739         // and restored it later (in execute()), but "break"
2740         // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
2741         // See http://bugs.busybox.net/view.php?id=846.
2742         // Now we do not touch t->op_words, but separately pass wp as param list
2743         // to builtins 
2744         DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2745                         no_fork, owp));
2746         /* Don't fork if it is a lone builtin (not in pipe)
2747          * OR we are told to _not_ fork */
2748         if ((!bltin || pin || pout)   /* not lone bltin AND */
2749          && !no_fork                  /* not told to avoid fork */
2750         ) {
2751                 /* Save values in case child alters them after vfork */
2752                 hpin = pin;
2753                 hpout = pout;
2754                 hwp = *wp;
2755                 hinteractive = interactive;
2756                 hintr = intr;
2757                 hbrklist = brklist;
2758                 hexecflg = execflg;
2759
2760                 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2761                 newpid = vfork();
2762                 if (newpid == -1) {
2763                         DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
2764                         return -1;
2765                 }
2766
2767                 if (newpid > 0) {  /* Parent */
2768                         /* Restore values */
2769                         pin = hpin;
2770                         pout = hpout;
2771                         *wp = hwp;
2772                         interactive = hinteractive;
2773                         intr = hintr;
2774                         brklist = hbrklist;
2775                         execflg = hexecflg;
2776
2777                         closepipe(pin);
2778                         return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2779                 }
2780
2781                 /* Child */
2782                 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
2783                 if (interactive) {
2784                         signal(SIGINT, SIG_IGN);
2785                         signal(SIGQUIT, SIG_IGN);
2786                         resetsig = 1;
2787                 }
2788                 interactive = 0;
2789                 intr = 0;
2790                 forked = 1;
2791                 brklist = 0;
2792                 execflg = 0;
2793         }
2794
2795         if (owp)
2796                 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2797                         if (!bltin)
2798                                 export(lookup(cp));
2799
2800         if (pin) { /* NB: close _first_, then move fds! */
2801                 close(pin[1]);
2802                 xmove_fd(pin[0], 0);
2803         }
2804         if (pout) {
2805                 close(pout[0]);
2806                 xmove_fd(pout[1], 1);
2807         }
2808
2809         iopp = t->ioact;
2810         if (iopp) {
2811                 if (bltin && bltin != doexec) {
2812                         prs(bltin_name);
2813                         err(": cannot redirect shell command");
2814                         if (forked)
2815                                 _exit(-1);
2816                         return -1;
2817                 }
2818                 while (*iopp) {
2819                         if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2820                                 /* system-detected error */
2821                                 if (forked)
2822                                         _exit(-1);
2823                                 return -1;
2824                         }
2825                 }
2826         }
2827
2828         if (bltin) {
2829                 if (forked || pin || pout) {
2830                         /* Builtin in pipe: disallowed */
2831                         /* TODO: allow "exec"? */
2832                         prs(bltin_name);
2833                         err(": cannot run builtin as part of pipe");
2834                         if (forked)
2835                                 _exit(-1);
2836                         return -1;
2837                 }
2838                 /* Run builtin */
2839                 i = setstatus(bltin(t, wp));
2840                 if (forked)
2841                         _exit(i);
2842                 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2843                 return i;
2844         }
2845
2846         /* should use FIOCEXCL */
2847         for (i = FDBASE; i < NOFILE; i++)
2848                 close(i);
2849         if (resetsig) {
2850                 signal(SIGINT, SIG_DFL);
2851                 signal(SIGQUIT, SIG_DFL);
2852         }
2853
2854         if (t->type == TPAREN)
2855                 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
2856         if (wp[0] == NULL)
2857                 _exit(0);
2858
2859         cp = rexecve(wp[0], wp, makenv(0, NULL));
2860         prs(wp[0]);
2861         prs(": ");
2862         err(cp);
2863         if (!execflg)
2864                 trap[0] = NULL;
2865
2866         DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
2867
2868         leave();
2869         /* NOTREACHED */
2870         return 0;
2871 }
2872
2873 /*
2874  * 0< 1> are ignored as required
2875  * within pipelines.
2876  */
2877 static int iosetup(struct ioword *iop, int pipein, int pipeout)
2878 {
2879         int u = -1;
2880         char *cp = NULL;
2881         const char *msg;
2882
2883         DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2884                            pipein, pipeout));
2885
2886         if (iop->io_unit == IODEFAULT)  /* take default */
2887                 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2888
2889         if (pipein && iop->io_unit == 0)
2890                 return 0;
2891
2892         if (pipeout && iop->io_unit == 1)
2893                 return 0;
2894
2895         msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2896         if ((iop->io_flag & IOHERE) == 0) {
2897                 cp = iop->io_name; /* huh?? */
2898                 cp = evalstr(cp, DOSUB | DOTRIM);
2899                 if (cp == NULL)
2900                         return 1;
2901         }
2902
2903         if (iop->io_flag & IODUP) {
2904                 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2905                         prs(cp);
2906                         err(": illegal >& argument");
2907                         return 1;
2908                 }
2909                 if (*cp == '-')
2910                         iop->io_flag = IOCLOSE;
2911                 iop->io_flag &= ~(IOREAD | IOWRITE);
2912         }
2913
2914         switch (iop->io_flag) {
2915         case IOREAD:
2916                 u = open(cp, O_RDONLY);
2917                 break;
2918
2919         case IOHERE:
2920         case IOHERE | IOXHERE:
2921                 u = herein(iop->io_name, iop->io_flag & IOXHERE);
2922                 cp = (char*)"here file";
2923                 break;
2924
2925         case IOWRITE | IOCAT:
2926                 u = open(cp, O_WRONLY);
2927                 if (u >= 0) {
2928                         lseek(u, (long) 0, SEEK_END);
2929                         break;
2930                 }
2931                 /* fall through to creation if >>file doesn't exist */
2932
2933         case IOWRITE:
2934                 u = creat(cp, 0666);
2935                 break;
2936
2937         case IODUP:
2938                 u = dup2(*cp - '0', iop->io_unit);
2939                 break;
2940
2941         case IOCLOSE:
2942                 close(iop->io_unit);
2943                 return 0;
2944         }
2945
2946         if (u < 0) {
2947                 prs(cp);
2948                 prs(": cannot ");
2949                 warn(msg);
2950                 return 1;
2951         }
2952         if (u != iop->io_unit) {
2953                 dup2(u, iop->io_unit);
2954                 close(u);
2955         }
2956         return 0;
2957 }
2958
2959 /*
2960  * Enter a new loop level (marked for break/continue).
2961  */
2962 static void brkset(struct brkcon *bc)
2963 {
2964         bc->nextlev = brklist;
2965         brklist = bc;
2966 }
2967
2968 /*
2969  * Wait for the last process created.
2970  * Print a message for each process found
2971  * that was killed by a signal.
2972  * Ignore interrupt signals while waiting
2973  * unless `canintr' is true.
2974  */
2975 static int waitfor(int lastpid, int canintr)
2976 {
2977         int pid, rv;
2978         int s;
2979         smallint oheedint = heedint;
2980
2981         heedint = 0;
2982         rv = 0;
2983         do {
2984                 pid = wait(&s);
2985                 if (pid == -1) {
2986                         if (errno != EINTR || canintr)
2987                                 break;
2988                 } else {
2989                         rv = WAITSIG(s);
2990                         if (rv != 0) {
2991                                 if (rv < ARRAY_SIZE(signame)) {
2992                                         if (signame[rv] != NULL) {
2993                                                 if (pid != lastpid) {
2994                                                         prn(pid);
2995                                                         prs(": ");
2996                                                 }
2997                                                 prs(signame[rv]);
2998                                         }
2999                                 } else {
3000                                         if (pid != lastpid) {
3001                                                 prn(pid);
3002                                                 prs(": ");
3003                                         }
3004                                         prs("Signal ");
3005                                         prn(rv);
3006                                         prs(" ");
3007                                 }
3008                                 if (WAITCORE(s))
3009                                         prs(" - core dumped");
3010                                 if (rv >= ARRAY_SIZE(signame) || signame[rv])
3011                                         prs("\n");
3012                                 rv = -1;
3013                         } else
3014                                 rv = WAITVAL(s);
3015                 }
3016         } while (pid != lastpid);
3017         heedint = oheedint;
3018         if (intr) {
3019                 if (interactive) {
3020                         if (canintr)
3021                                 intr = 0;
3022                 } else {
3023                         if (exstat == 0)
3024                                 exstat = rv;
3025                         onintr(0);
3026                 }
3027         }
3028         return rv;
3029 }
3030
3031 static int setstatus(int s)
3032 {
3033         exstat = s;
3034         setval(lookup("?"), putn(s));
3035         return s;
3036 }
3037
3038 /*
3039  * PATH-searching interface to execve.
3040  * If getenv("PATH") were kept up-to-date,
3041  * execvp might be used.
3042  */
3043 static const char *rexecve(char *c, char **v, char **envp)
3044 {
3045         const char *sp;
3046         char *tp;
3047         int asis = 0;
3048         char *name = c;
3049
3050         if (ENABLE_FEATURE_SH_STANDALONE) {
3051                 if (find_applet_by_name(name) >= 0) {
3052                         /* We have to exec here since we vforked.  Running
3053                          * run_applet_and_exit() won't work and bad things
3054                          * will happen. */
3055                         execve(bb_busybox_exec_path, v, envp);
3056                 }
3057         }
3058
3059         DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3060
3061         sp = any('/', c) ? "" : path->value;
3062         asis = (*sp == '\0');
3063         while (asis || *sp != '\0') {
3064                 asis = 0;
3065                 tp = global_env.linep;
3066                 for (; *sp != '\0'; tp++) {
3067                         *tp = *sp++;
3068                         if (*tp == ':') {
3069                                 asis = (*sp == '\0');
3070                                 break;
3071                         }
3072                 }
3073                 if (tp != global_env.linep)
3074                         *tp++ = '/';
3075                 strcpy(tp, c);
3076                 //for (i = 0; (*tp++ = c[i++]) != '\0';)
3077                 //      continue;
3078
3079                 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
3080
3081                 execve(global_env.linep, v, envp);
3082
3083                 switch (errno) {
3084                 case ENOEXEC:
3085                         *v = global_env.linep;
3086                         v--;
3087                         tp = *v;
3088                         *v = global_env.linep;
3089                         execve(DEFAULT_SHELL, v, envp);
3090                         *v = tp;
3091                         return "no shell";
3092
3093                 case ENOMEM:
3094                         return (char *) bb_msg_memory_exhausted;
3095
3096                 case E2BIG:
3097                         return "argument list too long";
3098                 }
3099         }
3100         return errno == ENOENT ? "not found" : "cannot execute";
3101 }
3102
3103 /*
3104  * Run the command produced by generator `f'
3105  * applied to stream `arg'.
3106  */
3107 static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3108 {
3109         struct op *otree;
3110         struct wdblock *swdlist;
3111         struct wdblock *siolist;
3112         jmp_buf ev, rt;
3113         xint *ofail;
3114         int rv;
3115
3116 #if __GNUC__
3117         /* Avoid longjmp clobbering */
3118         (void) &rv;
3119 #endif
3120
3121         DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3122                            areanum, outtree, failpt));
3123
3124         areanum++;
3125         swdlist = wdlist;
3126         siolist = iolist;
3127         otree = outtree;
3128         ofail = failpt;
3129         rv = -1;
3130
3131         errpt = ev;
3132         if (newenv(setjmp(errpt)) == 0) {
3133                 wdlist = 0;
3134                 iolist = 0;
3135                 pushio(argp, f);
3136                 global_env.iobase = global_env.iop;
3137                 yynerrs = 0;
3138                 failpt = rt;
3139                 if (setjmp(failpt) == 0 && yyparse() == 0)
3140                         rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
3141                 quitenv();
3142         } else {
3143                 DBGPRINTF(("RUN: error from newenv()!\n"));
3144         }
3145
3146         wdlist = swdlist;
3147         iolist = siolist;
3148         failpt = ofail;
3149         outtree = otree;
3150         freearea(areanum--);
3151
3152         return rv;
3153 }
3154
3155 /* -------- do.c -------- */
3156
3157 /*
3158  * built-in commands: doX
3159  */
3160
3161 static int dohelp(struct op *t, char **args)
3162 {
3163         int col;
3164         const struct builtincmd *x;
3165
3166         puts("\nBuilt-in commands:\n"
3167              "-------------------");
3168
3169         col = 0;
3170         x = builtincmds;
3171         while (x->name) {
3172                 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
3173                 if (col > 60) {
3174                         bb_putchar('\n');
3175                         col = 0;
3176                 }
3177                 x++;
3178         }
3179 #if ENABLE_FEATURE_SH_STANDALONE
3180         {
3181                 const char *applet = applet_names;
3182
3183                 while (*applet) {
3184                         col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
3185                         if (col > 60) {
3186                                 bb_putchar('\n');
3187                                 col = 0;
3188                         }
3189                         applet += strlen(applet) + 1;
3190                 }
3191         }
3192 #endif
3193         puts("\n");
3194         return EXIT_SUCCESS;
3195 }
3196
3197 static int dolabel(struct op *t, char **args)
3198 {
3199         return 0;
3200 }
3201
3202 static int dochdir(struct op *t, char **args)
3203 {
3204         const char *cp, *er;
3205
3206         cp = args[1];
3207         if (cp == NULL) {
3208                 cp = homedir->value;
3209                 if (cp != NULL)
3210                         goto do_cd;
3211                 er = ": no home directory";
3212         } else {
3213  do_cd:
3214                 if (chdir(cp) >= 0)
3215                         return 0;
3216                 er = ": bad directory";
3217         }
3218         prs(cp != NULL ? cp : "cd");
3219         err(er);
3220         return 1;
3221 }
3222
3223 static int doshift(struct op *t, char **args)
3224 {
3225         int n;
3226
3227         n = args[1] ? getn(args[1]) : 1;
3228         if (dolc < n) {
3229                 err("nothing to shift");
3230                 return 1;
3231         }
3232         dolv[n] = dolv[0];
3233         dolv += n;
3234         dolc -= n;
3235         setval(lookup("#"), putn(dolc));
3236         return 0;
3237 }
3238
3239 /*
3240  * execute login and newgrp directly
3241  */
3242 static int dologin(struct op *t, char **args)
3243 {
3244         const char *cp;
3245
3246         if (interactive) {
3247                 signal(SIGINT, SIG_DFL);
3248                 signal(SIGQUIT, SIG_DFL);
3249         }
3250         cp = rexecve(args[0], args, makenv(0, NULL));
3251         prs(args[0]);
3252         prs(": ");
3253         err(cp);
3254         return 1;
3255 }
3256
3257 static int doumask(struct op *t, char **args)
3258 {
3259         int i;
3260         char *cp;
3261
3262         cp = args[1];
3263         if (cp == NULL) {
3264                 i = umask(0);
3265                 umask(i);
3266                 printf("%04o\n", i);
3267         } else {
3268                 i = bb_strtou(cp, NULL, 8);
3269                 if (errno) {
3270                         err("umask: bad octal number");
3271                         return 1;
3272                 }
3273                 umask(i);
3274         }
3275         return 0;
3276 }
3277
3278 static int doexec(struct op *t, char **args)
3279 {
3280         jmp_buf ex;
3281         xint *ofail;
3282         char **sv_words;
3283
3284         t->ioact = NULL;
3285         if (!args[1])
3286                 return 1;
3287
3288         execflg = 1;
3289         ofail = failpt;
3290         failpt = ex;
3291
3292         sv_words = t->op_words;
3293         t->op_words = args + 1;
3294 // TODO: test what will happen with "exec break" -
3295 // will it leave t->op_words pointing to garbage?
3296 // (see http://bugs.busybox.net/view.php?id=846)
3297         if (setjmp(failpt) == 0)
3298                 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
3299         t->op_words = sv_words;
3300
3301         failpt = ofail;
3302         execflg = 0;
3303
3304         return 1;
3305 }
3306
3307 static int dodot(struct op *t, char **args)
3308 {
3309         int i;
3310         const char *sp;
3311         char *tp;
3312         char *cp;
3313         int maltmp;
3314
3315         DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3316                 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3317
3318         cp = args[1];
3319         if (cp == NULL) {
3320                 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3321                 return 0;
3322         }
3323         DBGPRINTF(("DODOT: cp is %s\n", cp));
3324
3325         sp = any('/', cp) ? ":" : path->value;
3326
3327         DBGPRINTF(("DODOT: sp is %s,  global_env.linep is %s\n",
3328                            ((sp == NULL) ? "NULL" : sp),
3329                            ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3330
3331         while (*sp) {
3332                 tp = global_env.linep;
3333                 while (*sp && (*tp = *sp++) != ':')
3334                         tp++;
3335                 if (tp != global_env.linep)
3336                         *tp++ = '/';
3337                 strcpy(tp, cp);
3338
3339                 /* Original code */
3340                 i = open(global_env.linep, O_RDONLY);
3341                 if (i >= 0) {
3342                         exstat = 0;
3343                         maltmp = remap(i);
3344                         DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3345                                 maltmp, exstat, global_env.iofd, i, global_env.linep));
3346
3347                         next(maltmp);           /* Basically a PUSHIO */
3348
3349                         DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3350
3351                         return exstat;
3352                 }
3353         } /* while */
3354
3355         prs(cp);
3356         err(": not found");
3357
3358         return -1;
3359 }
3360
3361 static int dowait(struct op *t, char **args)
3362 {
3363         int i;
3364         char *cp;
3365
3366         cp = args[1];
3367         if (cp != NULL) {
3368                 i = getn(cp);
3369                 if (i == 0)
3370                         return 0;
3371         } else
3372                 i = -1;
3373         setstatus(waitfor(i, 1));
3374         return 0;
3375 }
3376
3377 static int doread(struct op *t, char **args)
3378 {
3379         char *cp, **wp;
3380         int nb = 0;
3381         int nl = 0;
3382
3383         if (args[1] == NULL) {
3384                 err("Usage: read name ...");
3385                 return 1;
3386         }
3387         for (wp = args + 1; *wp; wp++) {
3388                 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
3389                         nb = nonblock_safe_read(0, cp, sizeof(*cp));
3390                         if (nb != sizeof(*cp))
3391                                 break;
3392                         nl = (*cp == '\n');
3393                         if (nl || (wp[1] && any(*cp, ifs->value)))
3394                                 break;
3395                 }
3396                 *cp = '\0';
3397                 if (nb <= 0)
3398                         break;
3399                 setval(lookup(*wp), global_env.linep);
3400         }
3401         return nb <= 0;
3402 }
3403
3404 static int doeval(struct op *t, char **args)
3405 {
3406         return RUN(awordlist, args + 1, wdchar);
3407 }
3408
3409 static int dotrap(struct op *t, char **args)
3410 {
3411         int n, i;
3412         int resetsig;
3413
3414         if (args[1] == NULL) {
3415                 for (i = 0; i <= _NSIG; i++)
3416                         if (trap[i]) {
3417                                 prn(i);
3418                                 prs(": ");
3419                                 prs(trap[i]);
3420                                 prs("\n");
3421                         }
3422                 return 0;
3423         }
3424         resetsig = isdigit(args[1][0]);
3425         for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3426                 n = getsig(args[i]);
3427                 freecell(trap[n]);
3428                 trap[n] = 0;
3429                 if (!resetsig) {
3430                         if (args[1][0] != '\0') {
3431                                 trap[n] = strsave(args[1], 0);
3432                                 setsig(n, sig);
3433                         } else
3434                                 setsig(n, SIG_IGN);
3435                 } else {
3436                         if (interactive) {
3437                                 if (n == SIGINT)
3438                                         setsig(n, onintr);
3439                                 else
3440                                         setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3441                         } else
3442                                 setsig(n, SIG_DFL);
3443                 }
3444         }
3445         return 0;
3446 }
3447
3448 static int getsig(char *s)
3449 {
3450         int n;
3451
3452         n = getn(s);
3453         if (n < 0 || n > _NSIG) {
3454                 err("trap: bad signal number");
3455                 n = 0;
3456         }
3457         return n;
3458 }
3459
3460 static void setsig(int n, sighandler_t f)
3461 {
3462         if (n == 0)
3463                 return;
3464         if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3465                 ourtrap[n] = 1;
3466                 signal(n, f);
3467         }
3468 }
3469
3470 static int getn(char *as)
3471 {
3472         char *s;
3473         int n, m;
3474
3475         s = as;
3476         m = 1;
3477         if (*s == '-') {
3478                 m = -1;
3479                 s++;
3480         }
3481         for (n = 0; isdigit(*s); s++)
3482                 n = (n * 10) + (*s - '0');
3483         if (*s) {
3484                 prs(as);
3485                 err(": bad number");
3486         }
3487         return n * m;
3488 }
3489
3490 static int dobreak(struct op *t, char **args)
3491 {
3492         return brkcontin(args[1], 1);
3493 }
3494
3495 static int docontinue(struct op *t, char **args)
3496 {
3497         return brkcontin(args[1], 0);
3498 }
3499
3500 static int brkcontin(char *cp, int val)
3501 {
3502         struct brkcon *bc;
3503         int nl;
3504
3505         nl = cp == NULL ? 1 : getn(cp);
3506         if (nl <= 0)
3507                 nl = 999;
3508         do {
3509                 bc = brklist;
3510                 if (bc == NULL)
3511                         break;
3512                 brklist = bc->nextlev;
3513         } while (--nl);
3514         if (nl) {
3515                 err("bad break/continue level");
3516                 return 1;
3517         }
3518         isbreak = (val != 0);
3519         longjmp(bc->brkpt, 1);
3520         /* NOTREACHED */
3521 }
3522
3523 static int doexit(struct op *t, char **args)
3524 {
3525         char *cp;
3526
3527         execflg = 0;
3528         cp = args[1];
3529         if (cp != NULL)
3530                 setstatus(getn(cp));
3531
3532         DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3533
3534         leave();
3535         /* NOTREACHED */
3536         return 0;
3537 }
3538
3539 static int doexport(struct op *t, char **args)
3540 {
3541         rdexp(args + 1, export, EXPORT);
3542         return 0;
3543 }
3544
3545 static int doreadonly(struct op *t, char **args)
3546 {
3547         rdexp(args + 1, ronly, RONLY);
3548         return 0;
3549 }
3550
3551 static void rdexp(char **wp, void (*f) (struct var *), int key)
3552 {
3553         DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3554         DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3555
3556         if (*wp != NULL) {
3557                 for (; *wp != NULL; wp++) {
3558                         if (isassign(*wp)) {
3559                                 char *cp;
3560
3561                                 assign(*wp, COPYV);
3562                                 for (cp = *wp; *cp != '='; cp++)
3563                                         continue;
3564                                 *cp = '\0';
3565                         }
3566                         if (checkname(*wp))
3567                                 (*f) (lookup(*wp));
3568                         else
3569                                 badid(*wp);
3570                 }
3571         } else
3572                 putvlist(key, 1);
3573 }
3574
3575 static void badid(char *s)
3576 {
3577         prs(s);
3578         err(": bad identifier");
3579 }
3580
3581 static int doset(struct op *t, char **args)
3582 {
3583         struct var *vp;
3584         char *cp;
3585         int n;
3586
3587         cp = args[1];
3588         if (cp == NULL) {
3589                 for (vp = vlist; vp; vp = vp->next)
3590                         varput(vp->name, 1);
3591                 return 0;
3592         }
3593         if (*cp == '-') {
3594                 args++;
3595                 if (*++cp == 0)
3596                         FLAG['x'] = FLAG['v'] = 0;
3597                 else {
3598                         for (; *cp; cp++) {
3599                                 switch (*cp) {
3600                                 case 'e':
3601                                         if (!interactive)
3602                                                 FLAG['e']++;
3603                                         break;
3604
3605                                 default:
3606                                         if (*cp >= 'a' && *cp <= 'z')
3607                                                 FLAG[(int) *cp]++;
3608                                         break;
3609                                 }
3610                         }
3611                 }
3612                 setdash();
3613         }
3614         if (args[1]) {
3615                 args[0] = dolv[0];
3616                 for (n = 1; args[n]; n++)
3617                         setarea((char *) args[n], 0);
3618                 dolc = n - 1;
3619                 dolv = args;
3620                 setval(lookup("#"), putn(dolc));
3621                 setarea((char *) (dolv - 1), 0);
3622         }
3623         return 0;
3624 }
3625
3626 static void varput(char *s, int out)
3627 {
3628         if (isalnum(*s) || *s == '_') {
3629                 write(out, s, strlen(s));
3630                 write(out, "\n", 1);
3631         }
3632 }
3633
3634
3635 /*
3636  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3637  * This file contains code for the times builtin.
3638  */
3639 static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3640 {
3641         unsigned min, sec;
3642         if (sizeof(val) > sizeof(int))
3643                 sec = ((unsigned long)val) / clk_tck;
3644         else
3645                 sec = ((unsigned)val) / clk_tck;
3646         min = sec / 60;
3647 #if ENABLE_DESKTOP
3648         sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3649         /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3650         );
3651 #else
3652         sprintf(buf, "%um%us", min, (sec - min * 60));
3653 #endif
3654 }
3655
3656 static int dotimes(struct op *t, char **args)
3657 {
3658         struct tms buf;
3659         unsigned clk_tck = sysconf(_SC_CLK_TCK);
3660         /* How much do we need for "NmN.NNNs" ? */
3661         enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3662         char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3663         char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
3664
3665         times(&buf);
3666
3667         times_fmt(u, buf.tms_utime, clk_tck);
3668         times_fmt(s, buf.tms_stime, clk_tck);
3669         times_fmt(cu, buf.tms_cutime, clk_tck);
3670         times_fmt(cs, buf.tms_cstime, clk_tck);
3671
3672         printf("%s %s\n%s %s\n", u, s, cu, cs);
3673         return 0;
3674 }
3675
3676
3677 /* -------- eval.c -------- */
3678
3679 /*
3680  * ${}
3681  * `command`
3682  * blank interpretation
3683  * quoting
3684  * glob
3685  */
3686
3687 static char **eval(char **ap, int f)
3688 {
3689         struct wdblock *wb;
3690         char **wp;
3691         char **wf;
3692         jmp_buf ev;
3693
3694 #if __GNUC__
3695         /* Avoid longjmp clobbering */
3696         (void) &wp;
3697         (void) &ap;
3698 #endif
3699
3700         DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3701
3702         wp = NULL;
3703         wb = NULL;
3704         wf = NULL;
3705         errpt = ev;
3706         if (newenv(setjmp(errpt)) == 0) {
3707                 while (*ap && isassign(*ap))
3708                         expand(*ap++, &wb, f & ~DOGLOB);
3709                 if (FLAG['k']) {
3710                         for (wf = ap; *wf; wf++) {
3711                                 if (isassign(*wf))
3712                                         expand(*wf, &wb, f & ~DOGLOB);
3713                         }
3714                 }
3715                 for (wb = addword((char *) NULL, wb); *ap; ap++) {
3716                         if (!FLAG['k'] || !isassign(*ap))
3717                                 expand(*ap, &wb, f & ~DOKEY);
3718                 }
3719                 wb = addword((char *) 0, wb);
3720                 wp = getwords(wb);
3721                 quitenv();
3722         } else
3723                 gflg = 1;
3724
3725         return gflg ? (char **) NULL : wp;
3726 }
3727
3728
3729 /*
3730  * Make the exported environment from the exported
3731  * names in the dictionary. Keyword assignments
3732  * will already have been done.
3733  */
3734 static char **makenv(int all, struct wdblock *wb)
3735 {
3736         struct var *vp;
3737
3738         DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3739
3740         for (vp = vlist; vp; vp = vp->next)
3741                 if (all || vp->status & EXPORT)
3742                         wb = addword(vp->name, wb);
3743         wb = addword((char *) 0, wb);
3744         return getwords(wb);
3745 }
3746
3747 static int expand(const char *cp, struct wdblock **wbp, int f)
3748 {
3749         jmp_buf ev;
3750         char *xp;
3751
3752 #if __GNUC__
3753         /* Avoid longjmp clobbering */
3754         (void) &cp;
3755 #endif
3756
3757         DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3758
3759         gflg = 0;
3760
3761         if (cp == NULL)
3762                 return 0;
3763
3764         if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3765          && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3766         ) {
3767                 xp = strsave(cp, areanum);
3768                 if (f & DOTRIM)
3769                         unquote(xp);
3770                 *wbp = addword(xp, *wbp);
3771                 return 1;
3772         }
3773         errpt = ev;
3774         if (newenv(setjmp(errpt)) == 0) {
3775                 PUSHIO(aword, cp, strchar);
3776                 global_env.iobase = global_env.iop;
3777                 while ((xp = blank(f)) && gflg == 0) {
3778                         global_env.linep = xp;
3779                         xp = strsave(xp, areanum);
3780                         if ((f & DOGLOB) == 0) {
3781                                 if (f & DOTRIM)
3782                                         unquote(xp);
3783                                 *wbp = addword(xp, *wbp);
3784                         } else
3785                                 *wbp = glob(xp, *wbp);
3786                 }
3787                 quitenv();
3788         } else
3789                 gflg = 1;
3790         return gflg == 0;
3791 }
3792
3793 static char *evalstr(char *cp, int f)
3794 {
3795         struct wdblock *wb;
3796
3797         DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3798
3799         wb = NULL;
3800         if (expand(cp, &wb, f)) {
3801                 if (wb == NULL || wb->w_nword == 0
3802                  || (cp = wb->w_words[0]) == NULL
3803                 ) {
3804 // TODO: I suspect that
3805 // char *evalstr(char *cp, int f)  is actually
3806 // const char *evalstr(const char *cp, int f)!
3807                         cp = (char*)"";
3808                 }
3809                 DELETE(wb);
3810         } else
3811                 cp = NULL;
3812         return cp;
3813 }
3814
3815
3816 /*
3817  * Blank interpretation and quoting
3818  */
3819 static char *blank(int f)
3820 {
3821         int c, c1;
3822         char *sp;
3823         int scanequals, foundequals;
3824
3825         DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3826
3827         sp = global_env.linep;
3828         scanequals = f & DOKEY;
3829         foundequals = 0;
3830
3831  loop:
3832         c = subgetc('"', foundequals);
3833         switch (c) {
3834         case 0:
3835                 if (sp == global_env.linep)
3836                         return 0;
3837                 *global_env.linep++ = 0;
3838                 return sp;
3839
3840         default:
3841                 if (f & DOBLANK && any(c, ifs->value))
3842                         goto loop;
3843                 break;
3844
3845         case '"':
3846         case '\'':
3847                 scanequals = 0;
3848                 if (INSUB())
3849                         break;
3850                 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3851                         if (c == 0)
3852                                 break;
3853                         if (c == '\'' || !any(c, "$`\""))
3854                                 c |= QUOTE;
3855                         *global_env.linep++ = c;
3856                 }
3857                 c = 0;
3858         }
3859         unget(c);
3860         if (!isalpha(c) && c != '_')
3861                 scanequals = 0;
3862         for (;;) {
3863                 c = subgetc('"', foundequals);
3864                 if (c == 0 ||
3865                         f & (DOBLANK && any(c, ifs->value)) ||
3866                         (!INSUB() && any(c, "\"'"))) {
3867                         scanequals = 0;
3868                         unget(c);
3869                         if (any(c, "\"'"))
3870                                 goto loop;
3871                         break;
3872                 }
3873                 if (scanequals) {
3874                         if (c == '=') {
3875                                 foundequals = 1;
3876                                 scanequals = 0;
3877                         } else if (!isalnum(c) && c != '_')
3878                                 scanequals = 0;
3879                 }
3880                 *global_env.linep++ = c;
3881         }
3882         *global_env.linep++ = 0;
3883         return sp;
3884 }
3885
3886 /*
3887  * Get characters, substituting for ` and $
3888  */
3889 static int subgetc(char ec, int quoted)
3890 {
3891         char c;
3892
3893         DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3894
3895  again:
3896         c = my_getc(ec);
3897         if (!INSUB() && ec != '\'') {
3898                 if (c == '`') {
3899                         if (grave(quoted) == 0)
3900                                 return 0;
3901                         global_env.iop->task = XGRAVE;
3902                         goto again;
3903                 }
3904                 if (c == '$') {
3905                         c = dollar(quoted);
3906                         if (c == 0) {
3907                                 global_env.iop->task = XDOLL;
3908                                 goto again;
3909                         }
3910                 }
3911         }
3912         return c;
3913 }
3914
3915 /*
3916  * Prepare to generate the string returned by ${} substitution.
3917  */
3918 static int dollar(int quoted)
3919 {
3920         int otask;
3921         struct io *oiop;
3922         char *dolp;
3923         char *s, c, *cp = NULL;
3924         struct var *vp;
3925
3926         DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3927
3928         c = readc();
3929         s = global_env.linep;
3930         if (c != '{') {
3931                 *global_env.linep++ = c;
3932                 if (isalpha(c) || c == '_') {
3933                         while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3934                                 if (global_env.linep < elinep)
3935                                         *global_env.linep++ = c;
3936                         unget(c);
3937                 }
3938                 c = 0;
3939         } else {
3940                 oiop = global_env.iop;
3941                 otask = global_env.iop->task;
3942
3943                 global_env.iop->task = XOTHER;
3944                 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3945                         if (global_env.linep < elinep)
3946                                 *global_env.linep++ = c;
3947                 if (oiop == global_env.iop)
3948                         global_env.iop->task = otask;
3949                 if (c != '}') {
3950                         err("unclosed ${");
3951                         gflg = 1;
3952                         return c;
3953                 }
3954         }
3955         if (global_env.linep >= elinep) {
3956                 err("string in ${} too long");
3957                 gflg = 1;
3958                 global_env.linep -= 10;
3959         }
3960         *global_env.linep = 0;
3961         if (*s)
3962                 for (cp = s + 1; *cp; cp++)
3963                         if (any(*cp, "=-+?")) {
3964                                 c = *cp;
3965                                 *cp++ = 0;
3966                                 break;
3967                         }
3968         if (s[1] == 0 && (*s == '*' || *s == '@')) {
3969                 if (dolc > 1) {
3970                         /* currently this does not distinguish $* and $@ */
3971                         /* should check dollar */
3972                         global_env.linep = s;
3973                         PUSHIO(awordlist, dolv + 1, dolchar);
3974                         return 0;
3975                 } else {                                /* trap the nasty ${=} */
3976                         s[0] = '1';
3977                         s[1] = '\0';
3978                 }
3979         }
3980         vp = lookup(s);
3981         dolp = vp->value;
3982         if (dolp == null) {
3983                 switch (c) {
3984                 case '=':
3985                         if (isdigit(*s)) {
3986                                 err("cannot use ${...=...} with $n");
3987                                 gflg = 1;
3988                                 break;
3989                         }
3990                         setval(vp, cp);
3991                         dolp = vp->value;
3992                         break;
3993
3994                 case '-':
3995                         dolp = strsave(cp, areanum);
3996                         break;
3997
3998                 case '?':
3999                         if (*cp == 0) {
4000                                 prs("missing value for ");
4001                                 err(s);
4002                         } else
4003                                 err(cp);
4004                         gflg = 1;
4005                         break;
4006                 }
4007         } else if (c == '+')
4008                 dolp = strsave(cp, areanum);
4009         if (FLAG['u'] && dolp == null) {
4010                 prs("unset variable: ");
4011                 err(s);
4012                 gflg = 1;
4013         }
4014         global_env.linep = s;
4015         PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4016         return 0;
4017 }
4018
4019 /*
4020  * Run the command in `...` and read its output.
4021  */
4022
4023 static int grave(int quoted)
4024 {
4025         /* moved to G: static char child_cmd[LINELIM]; */
4026
4027         const char *cp;
4028         int i;
4029         int j;
4030         int pf[2];
4031         const char *src;
4032         char *dest;
4033         int count;
4034         int ignore;
4035         int ignore_once;
4036         char *argument_list[4];
4037         struct wdblock *wb = NULL;
4038
4039 #if __GNUC__
4040         /* Avoid longjmp clobbering */
4041         (void) &cp;
4042 #endif
4043
4044         for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
4045                 if (*cp == 0) {
4046                         err("no closing `");
4047                         return 0;
4048                 }
4049         }
4050
4051         /* string copy with dollar expansion */
4052         src = global_env.iop->argp->aword;
4053         dest = child_cmd;
4054         count = 0;
4055         ignore = 0;
4056         ignore_once = 0;
4057         while ((*src != '`') && (count < LINELIM)) {
4058                 if (*src == '\'')
4059                         ignore = !ignore;
4060                 if (*src == '\\')
4061                         ignore_once = 1;
4062                 if (*src == '$' && !ignore && !ignore_once) {
4063                         struct var *vp;
4064                         /* moved to G to reduce stack usage
4065                         char var_name[LINELIM];
4066                         char alt_value[LINELIM];
4067                         */
4068 #define var_name (G.grave__var_name)
4069 #define alt_value (G.grave__alt_value)
4070                         int var_index = 0;
4071                         int alt_index = 0;
4072                         char operator = 0;
4073                         int braces = 0;
4074                         char *value;
4075
4076                         src++;
4077                         if (*src == '{') {
4078                                 braces = 1;
4079                                 src++;
4080                         }
4081
4082                         var_name[var_index++] = *src++;
4083                         while (isalnum(*src) || *src=='_')
4084                                 var_name[var_index++] = *src++;
4085                         var_name[var_index] = 0;
4086
4087                         if (braces) {
4088                                 switch (*src) {
4089                                 case '}':
4090                                         break;
4091                                 case '-':
4092                                 case '=':
4093                                 case '+':
4094                                 case '?':
4095                                         operator = * src;
4096                                         break;
4097                                 default:
4098                                         err("unclosed ${\n");
4099                                         return 0;
4100                                 }
4101                                 if (operator) {
4102                                         src++;
4103                                         while (*src && (*src != '}')) {
4104                                                 alt_value[alt_index++] = *src++;
4105                                         }
4106                                         alt_value[alt_index] = 0;
4107                                         if (*src != '}') {
4108                                                 err("unclosed ${\n");
4109                                                 return 0;
4110                                         }
4111                                 }
4112                                 src++;
4113                         }
4114
4115                         if (isalpha(*var_name)) {
4116                                 /* let subshell handle it instead */
4117
4118                                 char *namep = var_name;
4119
4120                                 *dest++ = '$';
4121                                 if (braces)
4122                                         *dest++ = '{';
4123                                 while (*namep)
4124                                         *dest++ = *namep++;
4125                                 if (operator) {
4126                                         char *altp = alt_value;
4127                                         *dest++ = operator;
4128                                         while (*altp)
4129                                                 *dest++ = *altp++;
4130                                 }
4131                                 if (braces)
4132                                         *dest++ = '}';
4133
4134                                 wb = addword(lookup(var_name)->name, wb);
4135                         } else {
4136                                 /* expand */
4137
4138                                 vp = lookup(var_name);
4139                                 if (vp->value != null)
4140                                         value = (operator == '+') ?
4141                                                 alt_value : vp->value;
4142                                 else if (operator == '?') {
4143                                         err(alt_value);
4144                                         return 0;
4145                                 } else if (alt_index && (operator != '+')) {
4146                                         value = alt_value;
4147                                         if (operator == '=')
4148                                                 setval(vp, value);
4149                                 } else
4150                                         continue;
4151
4152                                 while (*value && (count < LINELIM)) {
4153                                         *dest++ = *value++;
4154                                         count++;
4155                                 }
4156                         }
4157 #undef var_name
4158 #undef alt_value
4159                 } else {
4160                         *dest++ = *src++;
4161                         count++;
4162                         ignore_once = 0;
4163                 }
4164         }
4165         *dest = '\0';
4166
4167         if (openpipe(pf) < 0)
4168                 return 0;
4169
4170         while ((i = vfork()) == -1 && errno == EAGAIN)
4171                 continue;
4172
4173         DBGPRINTF3(("GRAVE: i is %p\n", io));
4174
4175         if (i < 0) {
4176                 closepipe(pf);
4177                 err((char *) bb_msg_memory_exhausted);
4178                 return 0;
4179         }
4180         if (i != 0) {
4181                 waitpid(i, NULL, 0); // safe_waitpid?
4182                 global_env.iop->argp->aword = ++cp;
4183                 close(pf[1]);
4184                 PUSHIO(afile, remap(pf[0]),
4185                         (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
4186                 return 1;
4187         }
4188         /* allow trapped signals */
4189         /* XXX - Maybe this signal stuff should go as well? */
4190         for (j = 0; j <= _NSIG; j++)
4191                 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4192                         signal(j, SIG_DFL);
4193
4194         /* Testcase where below checks are needed:
4195          * close stdout & run this script:
4196          *  files=`ls`
4197          *  echo "$files" >zz
4198          */
4199         xmove_fd(pf[1], 1);
4200         if (pf[0] != 1)
4201                 close(pf[0]);
4202
4203         argument_list[0] = (char *) DEFAULT_SHELL;
4204         argument_list[1] = (char *) "-c";
4205         argument_list[2] = child_cmd;
4206         argument_list[3] = NULL;
4207
4208         cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4209         prs(argument_list[0]);
4210         prs(": ");
4211         err(cp);
4212         _exit(1);
4213 }
4214
4215
4216 static char *unquote(char *as)
4217 {
4218         char *s;
4219
4220         s = as;
4221         if (s != NULL)
4222                 while (*s)
4223                         *s++ &= ~QUOTE;
4224         return as;
4225 }
4226
4227 /* -------- glob.c -------- */
4228
4229 /*
4230  * glob
4231  */
4232
4233 #define scopy(x) strsave((x), areanum)
4234 #define BLKSIZ  512
4235 #define NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4236
4237 static struct wdblock *cl, *nl;
4238 static const char spcl[] ALIGN1= "[?*";
4239
4240 static struct wdblock *glob(char *cp, struct wdblock *wb)
4241 {
4242         int i;
4243         char *pp;
4244
4245         if (cp == 0)
4246                 return wb;
4247         i = 0;
4248         for (pp = cp; *pp; pp++)
4249                 if (any(*pp, spcl))
4250                         i++;
4251                 else if (!any(*pp & ~QUOTE, spcl))
4252                         *pp &= ~QUOTE;
4253         if (i != 0) {
4254                 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
4255                         nl = newword(cl->w_nword * 2);
4256                         for (i = 0; i < cl->w_nword; i++) {     /* for each argument */
4257                                 for (pp = cl->w_words[i]; *pp; pp++)
4258                                         if (any(*pp, spcl)) {
4259                                                 globname(cl->w_words[i], pp);
4260                                                 break;
4261                                         }
4262                                 if (*pp == '\0')
4263                                         nl = addword(scopy(cl->w_words[i]), nl);
4264                         }
4265                         for (i = 0; i < cl->w_nword; i++)
4266                                 DELETE(cl->w_words[i]);
4267                         DELETE(cl);
4268                 }
4269                 if (cl->w_nword) {
4270                         for (i = 0; i < cl->w_nword; i++)
4271                                 unquote(cl->w_words[i]);
4272                         qsort_string_vector(cl->w_words, cl->w_nword);
4273                         for (i = 0; i < cl->w_nword; i++)
4274                                 wb = addword(cl->w_words[i], wb);
4275                         DELETE(cl);
4276                         return wb;
4277                 }
4278         }
4279         wb = addword(unquote(cp), wb);
4280         return wb;
4281 }
4282
4283 static void globname(char *we, char *pp)
4284 {
4285         char *np, *cp;
4286         char *name, *gp, *dp;
4287         int k;
4288         DIR *dirp;
4289         struct dirent *de;
4290         char dname[NAME_MAX + 1];
4291         struct stat dbuf;
4292
4293         for (np = we; np != pp; pp--)
4294                 if (pp[-1] == '/')
4295                         break;
4296         dp = cp = get_space((int) (pp - np) + 3);
4297         while (np < pp)
4298                 *cp++ = *np++;
4299         *cp++ = '.';
4300         *cp = '\0';
4301         gp = cp = get_space(strlen(pp) + 1);
4302         while (*np && *np != '/')
4303                 *cp++ = *np++;
4304         *cp = '\0';
4305         dirp = opendir(dp);
4306         if (dirp == 0) {
4307                 DELETE(dp);
4308                 DELETE(gp);
4309                 return;
4310         }
4311         dname[NAME_MAX] = '\0';
4312         while ((de = readdir(dirp)) != NULL) {
4313                 /* XXX Hmmm... What this could be? (abial) */
4314                 /*
4315                    if (ent[j].d_ino == 0)
4316                       continue;
4317                  */
4318                 strncpy(dname, de->d_name, NAME_MAX);
4319                 if (dname[0] == '.')
4320                         if (*gp != '.')
4321                                 continue;
4322                 for (k = 0; k < NAME_MAX; k++)
4323                         if (any(dname[k], spcl))
4324                                 dname[k] |= QUOTE;
4325                 if (gmatch(dname, gp)) {
4326                         name = generate(we, pp, dname, np);
4327                         if (*np && !anys(np, spcl)) {
4328                                 if (stat(name, &dbuf)) {
4329                                         DELETE(name);
4330                                         continue;
4331                                 }
4332                         }
4333                         nl = addword(name, nl);
4334                 }
4335         }
4336         closedir(dirp);
4337         DELETE(dp);
4338         DELETE(gp);
4339 }
4340
4341 /*
4342  * generate a pathname as below.
4343  * start..end1 / middle end
4344  * the slashes come for free
4345  */
4346 static char *generate(char *start1, char *end1, char *middle, char *end)
4347 {
4348         char *p;
4349         char *op, *xp;
4350
4351         p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4352         xp = start1;
4353         while (xp != end1)
4354                 *op++ = *xp++;
4355         xp = middle;
4356         while (*xp != '\0')
4357                 *op++ = *xp++;
4358         strcpy(op, end);
4359         return p;
4360 }
4361
4362 static int anyspcl(struct wdblock *wb)
4363 {
4364         int i;
4365         char **wd;
4366
4367         wd = wb->w_words;
4368         for (i = 0; i < wb->w_nword; i++)
4369                 if (anys(spcl, *wd++))
4370                         return 1;
4371         return 0;
4372 }
4373
4374
4375 /* -------- word.c -------- */
4376
4377 static struct wdblock *newword(int nw)
4378 {
4379         struct wdblock *wb;
4380
4381         wb = get_space(sizeof(*wb) + nw * sizeof(char *));
4382         wb->w_bsize = nw;
4383         wb->w_nword = 0;
4384         return wb;
4385 }
4386
4387 static struct wdblock *addword(char *wd, struct wdblock *wb)
4388 {
4389         struct wdblock *wb2;
4390         int nw;
4391
4392         if (wb == NULL)
4393                 wb = newword(NSTART);
4394         nw = wb->w_nword;
4395         if (nw >= wb->w_bsize) {
4396                 wb2 = newword(nw * 2);
4397                 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4398                            nw * sizeof(char *));
4399                 wb2->w_nword = nw;
4400                 DELETE(wb);
4401                 wb = wb2;
4402         }
4403         wb->w_words[wb->w_nword++] = wd;
4404         return wb;
4405 }
4406
4407 static char **getwords(struct wdblock *wb)
4408 {
4409         char **wd;
4410         int nb;
4411
4412         if (wb == NULL)
4413                 return NULL;
4414         if (wb->w_nword == 0) {
4415                 DELETE(wb);
4416                 return NULL;
4417         }
4418         nb = sizeof(*wd) * wb->w_nword;
4419         wd = get_space(nb);
4420         memcpy(wd, wb->w_words, nb);
4421         DELETE(wb);                     /* perhaps should done by caller */
4422         return wd;
4423 }
4424
4425
4426 /* -------- io.c -------- */
4427
4428 /*
4429  * shell IO
4430  */
4431
4432 static int my_getc(int ec)
4433 {
4434         int c;
4435
4436         if (global_env.linep > elinep) {
4437                 while ((c = readc()) != '\n' && c)
4438                         continue;
4439                 err("input line too long");
4440                 gflg = 1;
4441                 return c;
4442         }
4443         c = readc();
4444         if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
4445                 if (c == '\\') {
4446                         c = readc();
4447                         if (c == '\n' && ec != '\"')
4448                                 return my_getc(ec);
4449                         c |= QUOTE;
4450                 }
4451         }
4452         return c;
4453 }
4454
4455 static void unget(int c)
4456 {
4457         if (global_env.iop >= global_env.iobase)
4458                 global_env.iop->peekc = c;
4459 }
4460
4461 static int eofc(void)
4462 {
4463         return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
4464 }
4465
4466 static int readc(void)
4467 {
4468         int c;
4469
4470         RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
4471
4472         for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4473                 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4474                 c = global_env.iop->peekc;
4475                 if (c != '\0') {
4476                         global_env.iop->peekc = 0;
4477                         return c;
4478                 }
4479                 if (global_env.iop->prev != 0) {
4480                         c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
4481                         if (c != '\0') {
4482                                 if (c == -1) {
4483                                         global_env.iop++;
4484                                         continue;
4485                                 }
4486                                 if (global_env.iop == iostack)
4487                                         ioecho(c);
4488                                 global_env.iop->prev = c;
4489                                 return global_env.iop->prev;
4490                         }
4491                         if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4492                                 global_env.iop->prev = 0;
4493                                 if (global_env.iop == iostack)
4494                                         ioecho('\n');
4495                                 return '\n';
4496                         }
4497                 }
4498                 if (global_env.iop->task == XIO) {
4499                         if (multiline) {
4500                                 global_env.iop->prev = 0;
4501                                 return global_env.iop->prev;
4502                         }
4503                         if (interactive && global_env.iop == iostack + 1) {
4504 #if ENABLE_FEATURE_EDITING
4505                                 current_prompt = prompt->value;
4506 #else
4507                                 prs(prompt->value);
4508 #endif
4509                         }
4510                 }
4511         }                                                       /* FOR */
4512
4513         if (global_env.iop >= iostack) {
4514                 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
4515                 return 0;
4516         }
4517
4518         DBGPRINTF(("READC: leave()...\n"));
4519         leave();
4520         /* NOTREACHED */
4521         return 0;
4522 }
4523
4524 static void ioecho(char c)
4525 {
4526         if (FLAG['v'])
4527                 write(2, &c, sizeof c);
4528 }
4529
4530 static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4531 {
4532         DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4533                            argp->afid, global_env.iop));
4534
4535         /* Set env ptr for io source to next array spot and check for array overflow */
4536         if (++global_env.iop >= &iostack[NPUSH]) {
4537                 global_env.iop--;
4538                 err("Shell input nested too deeply");
4539                 gflg = 1;
4540                 return;
4541         }
4542
4543         /* We did not overflow the NPUSH array spots so setup data structs */
4544
4545         global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn;       /* Store data source func ptr */
4546
4547         if (argp->afid != AFID_NOBUF)
4548                 global_env.iop->argp = argp;
4549         else {
4550
4551                 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4552                 *global_env.iop->argp = *argp;  /* copy data from temp area into stack spot */
4553
4554                 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4555
4556                 if (global_env.iop == &iostack[0])
4557                         global_env.iop->argp->afbuf = &mainbuf;
4558                 else
4559                         global_env.iop->argp->afbuf = &sharedbuf;
4560
4561                 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4562                 /* This line appears to be active when running scripts from command line */
4563                 if ((isatty(global_env.iop->argp->afile) == 0)
4564                         && (global_env.iop == &iostack[0]
4565                                 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4566                         if (++bufid == AFID_NOBUF)      /* counter rollover check, AFID_NOBUF = 11111111  */
4567                                 bufid = AFID_ID;        /* AFID_ID = 0 */
4568
4569                         global_env.iop->argp->afid = bufid;     /* assign buffer id */
4570                 }
4571
4572                 DBGPRINTF(("PUSHIO: iostack %p,  global_env.iop %p, afbuf %p\n",
4573                                    iostack, global_env.iop, global_env.iop->argp->afbuf));
4574                 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4575                                    &mainbuf, &sharedbuf, bufid, global_env.iop));
4576
4577         }
4578
4579         global_env.iop->prev = ~'\n';
4580         global_env.iop->peekc = 0;
4581         global_env.iop->xchar = 0;
4582         global_env.iop->nlcount = 0;
4583
4584         if (fn == filechar || fn == linechar)
4585                 global_env.iop->task = XIO;
4586         else if (fn == (int (*)(struct ioarg *)) gravechar
4587          || fn == (int (*)(struct ioarg *)) qgravechar)
4588                 global_env.iop->task = XGRAVE;
4589         else
4590                 global_env.iop->task = XOTHER;
4591 }
4592
4593 static struct io *setbase(struct io *ip)
4594 {
4595         struct io *xp;
4596
4597         xp = global_env.iobase;
4598         global_env.iobase = ip;
4599         return xp;
4600 }
4601
4602 /*
4603  * Input generating functions
4604  */
4605
4606 /*
4607  * Produce the characters of a string, then a newline, then EOF.
4608  */
4609 static int nlchar(struct ioarg *ap)
4610 {
4611         int c;
4612
4613         if (ap->aword == NULL)
4614                 return 0;
4615         c = *ap->aword++;
4616         if (c == 0) {
4617                 ap->aword = NULL;
4618                 return '\n';
4619         }
4620         return c;
4621 }
4622
4623 /*
4624  * Given a list of words, produce the characters
4625  * in them, with a space after each word.
4626  */
4627 static int wdchar(struct ioarg *ap)
4628 {
4629         char c;
4630         char **wl;
4631
4632         wl = ap->awordlist;
4633         if (wl == NULL)
4634                 return 0;
4635         if (*wl != NULL) {
4636                 c = *(*wl)++;
4637                 if (c != 0)
4638                         return c & 0177;
4639                 ap->awordlist++;
4640                 return ' ';
4641         }
4642         ap->awordlist = NULL;
4643         return '\n';
4644 }
4645
4646 /*
4647  * Return the characters of a list of words,
4648  * producing a space between them.
4649  */
4650 static int dolchar(struct ioarg *ap)
4651 {
4652         char *wp;
4653
4654         wp = *ap->awordlist++;
4655         if (wp != NULL) {
4656                 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4657                 return -1;
4658         }
4659         return 0;
4660 }
4661
4662 static int xxchar(struct ioarg *ap)
4663 {
4664         int c;
4665
4666         if (ap->aword == NULL)
4667                 return 0;
4668         c = *ap->aword++;
4669         if (c == '\0') {
4670                 ap->aword = NULL;
4671                 return ' ';
4672         }
4673         return c;
4674 }
4675
4676 /*
4677  * Produce the characters from a single word (string).
4678  */
4679 static int strchar(struct ioarg *ap)
4680 {
4681         if (ap->aword == NULL)
4682                 return 0;
4683         return *ap->aword++;
4684 }
4685
4686 /*
4687  * Produce quoted characters from a single word (string).
4688  */
4689 static int qstrchar(struct ioarg *ap)
4690 {
4691         int c;
4692
4693         if (ap->aword == NULL)
4694                 return 0;
4695         c = *ap->aword++;
4696         if (c)
4697                 c |= QUOTE;
4698         return c;
4699 }
4700
4701 /*
4702  * Return the characters from a file.
4703  */
4704 static int filechar(struct ioarg *ap)
4705 {
4706         int i;
4707         char c;
4708         struct iobuf *bp = ap->afbuf;
4709
4710         if (ap->afid != AFID_NOBUF) {
4711                 i = (ap->afid != bp->id);
4712                 if (i || bp->bufp == bp->ebufp) {
4713                         if (i)
4714                                 lseek(ap->afile, ap->afpos, SEEK_SET);
4715
4716                         i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4717                         if (i <= 0) {
4718                                 closef(ap->afile);
4719                                 return 0;
4720                         }
4721
4722                         bp->id = ap->afid;
4723                         bp->bufp = bp->buf;
4724                         bp->ebufp = bp->bufp + i;
4725                 }
4726
4727                 ap->afpos++;
4728                 return *bp->bufp++ & 0177;
4729         }
4730 #if ENABLE_FEATURE_EDITING
4731         if (interactive && isatty(ap->afile)) {
4732                 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
4733                 static int position = 0, size = 0;
4734
4735                 while (size == 0 || position >= size) {
4736                         size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4737                         if (size < 0) /* Error/EOF */
4738                                 exit(0);
4739                         position = 0;
4740                         /* if Ctrl-C, size == 0 and loop will repeat */
4741                 }
4742                 c = filechar_cmdbuf[position];
4743                 position++;
4744                 return c;
4745         }
4746 #endif
4747         i = nonblock_safe_read(ap->afile, &c, sizeof(c));
4748         return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4749 }
4750
4751 /*
4752  * Return the characters from a here temp file.
4753  */
4754 static int herechar(struct ioarg *ap)
4755 {
4756         char c;
4757
4758         if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4759                 close(ap->afile);
4760                 c = '\0';
4761         }
4762         return c;
4763 }
4764
4765 /*
4766  * Return the characters produced by a process (`...`).
4767  * Quote them if required, and remove any trailing newline characters.
4768  */
4769 static int gravechar(struct ioarg *ap, struct io *iop)
4770 {
4771         int c;
4772
4773         c = qgravechar(ap, iop) & ~QUOTE;
4774         if (c == '\n')
4775                 c = ' ';
4776         return c;
4777 }
4778
4779 static int qgravechar(struct ioarg *ap, struct io *iop)
4780 {
4781         int c;
4782
4783         DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4784
4785         if (iop->xchar) {
4786                 if (iop->nlcount) {
4787                         iop->nlcount--;
4788                         return '\n' | QUOTE;
4789                 }
4790                 c = iop->xchar;
4791                 iop->xchar = 0;
4792         } else if ((c = filechar(ap)) == '\n') {
4793                 iop->nlcount = 1;
4794                 while ((c = filechar(ap)) == '\n')
4795                         iop->nlcount++;
4796                 iop->xchar = c;
4797                 if (c == 0)
4798                         return c;
4799                 iop->nlcount--;
4800                 c = '\n';
4801         }
4802         return c != 0 ? c | QUOTE : 0;
4803 }
4804
4805 /*
4806  * Return a single command (usually the first line) from a file.
4807  */
4808 static int linechar(struct ioarg *ap)
4809 {
4810         int c;
4811
4812         c = filechar(ap);
4813         if (c == '\n') {
4814                 if (!multiline) {
4815                         closef(ap->afile);
4816                         ap->afile = -1;         /* illegal value */
4817                 }
4818         }
4819         return c;
4820 }
4821
4822 /*
4823  * remap fd into Shell's fd space
4824  */
4825 static int remap(int fd)
4826 {
4827         int i;
4828         int map[NOFILE];
4829         int newfd;
4830
4831         DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
4832
4833         if (fd < global_env.iofd) {
4834                 for (i = 0; i < NOFILE; i++)
4835                         map[i] = 0;
4836
4837                 do {
4838                         map[fd] = 1;
4839                         newfd = dup(fd);
4840                         fd = newfd;
4841                 } while (fd >= 0 && fd < global_env.iofd);
4842
4843                 for (i = 0; i < NOFILE; i++)
4844                         if (map[i])
4845                                 close(i);
4846
4847                 if (fd < 0)
4848                         err("too many files open in shell");
4849         }
4850
4851         return fd;
4852 }
4853
4854 static int openpipe(int *pv)
4855 {
4856         int i;
4857
4858         i = pipe(pv);
4859         if (i < 0)
4860                 err("can't create pipe - try again");
4861         return i;
4862 }
4863
4864 static void closepipe(int *pv)
4865 {
4866         if (pv != NULL) {
4867                 close(pv[0]);
4868                 close(pv[1]);
4869         }
4870 }
4871
4872
4873 /* -------- here.c -------- */
4874
4875 /*
4876  * here documents
4877  */
4878
4879 static void markhere(char *s, struct ioword *iop)
4880 {
4881         struct here *h, *lh;
4882
4883         DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
4884
4885         h = get_space(sizeof(struct here));
4886         if (h == NULL)
4887                 return;
4888
4889         h->h_tag = evalstr(s, DOSUB);
4890         if (h->h_tag == 0)
4891                 return;
4892
4893         h->h_iop = iop;
4894         iop->io_name = 0;
4895         h->h_next = NULL;
4896         if (inhere == 0)
4897                 inhere = h;
4898         else {
4899                 for (lh = inhere; lh != NULL; lh = lh->h_next) {
4900                         if (lh->h_next == 0) {
4901                                 lh->h_next = h;
4902                                 break;
4903                         }
4904                 }
4905         }
4906         iop->io_flag |= IOHERE | IOXHERE;
4907         for (s = h->h_tag; *s; s++) {
4908                 if (*s & QUOTE) {
4909                         iop->io_flag &= ~IOXHERE;
4910                         *s &= ~QUOTE;
4911                 }
4912         }
4913         h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
4914 }
4915
4916 static void gethere(void)
4917 {
4918         struct here *h, *hp;
4919
4920         DBGPRINTF7(("GETHERE: enter...\n"));
4921
4922         /* Scan here files first leaving inhere list in place */
4923         for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
4924                 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
4925
4926         /* Make inhere list active - keep list intact for scraphere */
4927         if (hp != NULL) {
4928                 hp->h_next = acthere;
4929                 acthere = inhere;
4930                 inhere = NULL;
4931         }
4932 }
4933
4934 static void readhere(char **name, char *s, int ec)
4935 {
4936         int tf;
4937         char tname[30] = ".msh_XXXXXX";
4938         int c;
4939         jmp_buf ev;
4940         char myline[LINELIM + 1];
4941         char *thenext;
4942
4943         DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
4944
4945         tf = mkstemp(tname);
4946         if (tf < 0)
4947                 return;
4948
4949         *name = strsave(tname, areanum);
4950         errpt = ev;
4951         if (newenv(setjmp(errpt)) != 0)
4952                 unlink(tname);
4953         else {
4954                 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4955                 global_env.iobase = global_env.iop;
4956                 for (;;) {
4957                         if (interactive && global_env.iop <= iostack) {
4958 #if ENABLE_FEATURE_EDITING
4959                                 current_prompt = cprompt->value;
4960 #else
4961                                 prs(cprompt->value);
4962 #endif
4963                         }
4964                         thenext = myline;
4965                         while ((c = my_getc(ec)) != '\n' && c) {
4966                                 if (ec == '\'')
4967                                         c &= ~QUOTE;
4968                                 if (thenext >= &myline[LINELIM]) {
4969                                         c = 0;
4970                                         break;
4971                                 }
4972                                 *thenext++ = c;
4973                         }
4974                         *thenext = 0;
4975                         if (strcmp(s, myline) == 0 || c == 0)
4976                                 break;
4977                         *thenext++ = '\n';
4978                         write(tf, myline, (int) (thenext - myline));
4979                 }
4980                 if (c == 0) {
4981                         prs("here document `");
4982                         prs(s);
4983                         err("' unclosed");
4984                 }
4985                 quitenv();
4986         }
4987         close(tf);
4988 }
4989
4990 /*
4991  * open here temp file.
4992  * if unquoted here, expand here temp file into second temp file.
4993  */
4994 static int herein(char *hname, int xdoll)
4995 {
4996         int hf;
4997         int tf;
4998
4999 #if __GNUC__
5000         /* Avoid longjmp clobbering */
5001         (void) &tf;
5002 #endif
5003         if (hname == NULL)
5004                 return -1;
5005
5006         DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5007
5008         hf = open(hname, O_RDONLY);
5009         if (hf < 0)
5010                 return -1;
5011
5012         if (xdoll) {
5013                 char c;
5014                 char tname[30] = ".msh_XXXXXX";
5015                 jmp_buf ev;
5016
5017                 tf = mkstemp(tname);
5018                 if (tf < 0)
5019                         return -1;
5020                 errpt = ev;
5021                 if (newenv(setjmp(errpt)) == 0) {
5022                         PUSHIO(afile, hf, herechar);
5023                         setbase(global_env.iop);
5024                         while ((c = subgetc(0, 0)) != 0) {
5025                                 c &= ~QUOTE;
5026                                 write(tf, &c, sizeof c);
5027                         }
5028                         quitenv();
5029                 } else
5030                         unlink(tname);
5031                 close(tf);
5032                 tf = open(tname, O_RDONLY);
5033                 unlink(tname);
5034                 return tf;
5035         }
5036         return hf;
5037 }
5038
5039 static void scraphere(void)
5040 {
5041         struct here *h;
5042
5043         DBGPRINTF7(("SCRAPHERE: enter...\n"));
5044
5045         for (h = inhere; h != NULL; h = h->h_next) {
5046                 if (h->h_iop && h->h_iop->io_name)
5047                         unlink(h->h_iop->io_name);
5048         }
5049         inhere = NULL;
5050 }
5051
5052 /* unlink here temp files before a freearea(area) */
5053 static void freehere(int area)
5054 {
5055         struct here *h, *hl;
5056
5057         DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5058
5059         hl = NULL;
5060         for (h = acthere; h != NULL; h = h->h_next)
5061                 if (getarea((char *) h) >= area) {
5062                         if (h->h_iop->io_name != NULL)
5063                                 unlink(h->h_iop->io_name);
5064                         if (hl == NULL)
5065                                 acthere = h->h_next;
5066                         else
5067                                 hl->h_next = h->h_next;
5068                 } else
5069                         hl = h;
5070 }
5071
5072
5073 /* -------- sh.c -------- */
5074 /*
5075  * shell
5076  */
5077
5078 int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
5079 int msh_main(int argc, char **argv)
5080 {
5081         int f;
5082         char *s;
5083         int cflag;
5084         char *name, **ap;
5085         int (*iof) (struct ioarg *);
5086
5087         INIT_G();
5088
5089         sharedbuf.id = AFID_NOBUF;
5090         mainbuf.id = AFID_NOBUF;
5091         elinep = line + sizeof(line) - 5;
5092
5093 #if ENABLE_FEATURE_EDITING
5094         line_input_state = new_line_input_t(FOR_SHELL);
5095 #endif
5096
5097         DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5098
5099         initarea();
5100         ap = environ;
5101         if (ap != NULL) {
5102                 while (*ap)
5103                         assign(*ap++, !COPYV);
5104                 for (ap = environ; *ap;)
5105                         export(lookup(*ap++));
5106         }
5107         closeall();
5108         areanum = 1;
5109
5110         shell = lookup("SHELL");
5111         if (shell->value == null)
5112                 setval(shell, (char *)DEFAULT_SHELL);
5113         export(shell);
5114
5115         homedir = lookup("HOME");
5116         if (homedir->value == null)
5117                 setval(homedir, "/");
5118         export(homedir);
5119
5120         setval(lookup("$"), putn(getpid()));
5121
5122         path = lookup("PATH");
5123         if (path->value == null) {
5124                 /* Can be merged with same string elsewhere in bbox */
5125                 if (geteuid() == 0)
5126                         setval(path, bb_default_root_path);
5127                 else
5128                         setval(path, bb_default_path);
5129         }
5130         export(path);
5131
5132         ifs = lookup("IFS");
5133         if (ifs->value == null)
5134                 setval(ifs, " \t\n");
5135
5136 #ifdef MSHDEBUG
5137         mshdbg_var = lookup("MSHDEBUG");
5138         if (mshdbg_var->value == null)
5139                 setval(mshdbg_var, "0");
5140 #endif
5141
5142         prompt = lookup("PS1");
5143 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5144         if (prompt->value == null)
5145 #endif
5146                 setval(prompt, DEFAULT_USER_PROMPT);
5147         if (geteuid() == 0) {
5148                 setval(prompt, DEFAULT_ROOT_PROMPT);
5149                 prompt->status &= ~EXPORT;
5150         }
5151         cprompt = lookup("PS2");
5152 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5153         if (cprompt->value == null)
5154 #endif
5155                 setval(cprompt, "> ");
5156
5157         iof = filechar;
5158         cflag = 0;
5159         name = *argv++;
5160         if (--argc >= 1) {
5161                 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5162                         for (s = argv[0] + 1; *s; s++)
5163                                 switch (*s) {
5164                                 case 'c':
5165                                         prompt->status &= ~EXPORT;
5166                                         cprompt->status &= ~EXPORT;
5167                                         setval(prompt, "");
5168                                         setval(cprompt, "");
5169                                         cflag = 1;
5170                                         if (--argc > 0)
5171                                                 PUSHIO(aword, *++argv, iof = nlchar);
5172                                         break;
5173
5174                                 case 'q':
5175                                         qflag = SIG_DFL;
5176                                         break;
5177
5178                                 case 's':
5179                                         /* standard input */
5180                                         break;
5181
5182                                 case 't':
5183                                         prompt->status &= ~EXPORT;
5184                                         setval(prompt, "");
5185                                         iof = linechar;
5186                                         break;
5187
5188                                 case 'i':
5189                                         interactive = 1;
5190                                 default:
5191                                         if (*s >= 'a' && *s <= 'z')
5192                                                 FLAG[(int) *s]++;
5193                                 }
5194                 } else {
5195                         argv--;
5196                         argc++;
5197                 }
5198
5199                 if (iof == filechar && --argc > 0) {
5200                         setval(prompt, "");
5201                         setval(cprompt, "");
5202                         prompt->status &= ~EXPORT;
5203                         cprompt->status &= ~EXPORT;
5204
5205 /* Shell is non-interactive, activate printf-based debug */
5206 #ifdef MSHDEBUG
5207                         mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5208                         if (mshdbg < 0)
5209                                 mshdbg = 0;
5210 #endif
5211                         DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5212
5213                         name = *++argv;
5214                         if (newfile(name))
5215                                 exit(1);                /* Exit on error */
5216                 }
5217         }
5218
5219         setdash();
5220
5221         /* This won't be true if PUSHIO has been called, say from newfile() above */
5222         if (global_env.iop < iostack) {
5223                 PUSHIO(afile, 0, iof);
5224                 if (isatty(0) && isatty(1) && !cflag) {
5225                         interactive = 1;
5226 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
5227 #ifdef MSHDEBUG
5228                         printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
5229 #else
5230                         printf("\n\n%s built-in shell (msh)\n", bb_banner);
5231 #endif
5232                         printf("Enter 'help' for a list of built-in commands.\n\n");
5233 #endif
5234                 }
5235         }
5236
5237         signal(SIGQUIT, qflag);
5238         if (name && name[0] == '-') {
5239                 interactive = 1;
5240                 f = open(".profile", O_RDONLY);
5241                 if (f >= 0)
5242                         next(remap(f));
5243                 f = open("/etc/profile", O_RDONLY);
5244                 if (f >= 0)
5245                         next(remap(f));
5246         }
5247         if (interactive)
5248                 signal(SIGTERM, sig);
5249
5250         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5251                 signal(SIGINT, onintr);
5252
5253 /* Handle "msh SCRIPT VAR=val params..." */
5254 /* Disabled: bash does not do it! */
5255 #if 0
5256         argv++;
5257         /* skip leading args of the form VAR=val */
5258         while (*argv && assign(*argv, !COPYV)) {
5259                 argc--;
5260                 argv++;
5261         }
5262         argv--;
5263 #endif
5264         dolv = argv;
5265         dolc = argc;
5266         dolv[0] = name;
5267
5268         setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5269
5270         DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
5271
5272         for (;;) {
5273                 if (interactive && global_env.iop <= iostack) {
5274 #if ENABLE_FEATURE_EDITING
5275                         current_prompt = prompt->value;
5276 #else
5277                         prs(prompt->value);
5278 #endif
5279                 }
5280                 onecommand();
5281                 /* Ensure that getenv("PATH") stays current */
5282                 setenv("PATH", path->value, 1);
5283         }
5284
5285         DBGPRINTF(("MSH_MAIN: returning.\n"));
5286 }
5287
5288
5289 /*
5290  * Copyright (c) 1987,1997, Prentice Hall
5291  * All rights reserved.
5292  *
5293  * Redistribution and use of the MINIX operating system in source and
5294  * binary forms, with or without modification, are permitted provided
5295  * that the following conditions are met:
5296  *
5297  * Redistributions of source code must retain the above copyright
5298  * notice, this list of conditions and the following disclaimer.
5299  *
5300  * Redistributions in binary form must reproduce the above
5301  * copyright notice, this list of conditions and the following
5302  * disclaimer in the documentation and/or other materials provided
5303  * with the distribution.
5304  *
5305  * Neither the name of Prentice Hall nor the names of the software
5306  * authors or contributors may be used to endorse or promote
5307  * products derived from this software without specific prior
5308  * written permission.
5309  *
5310  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5311  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5312  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5313  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5314  * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5315  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5316  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5317  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5318  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5319  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5320  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5321  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5322  *
5323  */