hush: mention PPID, RANDOM support
[oweals/busybox.git] / shell / msh_unused.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 #include <sys/times.h>
16 #include <setjmp.h>
17
18 #ifdef STANDALONE
19 # ifndef _GNU_SOURCE
20 #  define _GNU_SOURCE
21 # endif
22 # include <sys/types.h>
23 # include <sys/stat.h>
24 # include <sys/wait.h>
25 # include <signal.h>
26 # include <stdio.h>
27 # include <stdlib.h>
28 # include <unistd.h>
29 # include <string.h>
30 # include <errno.h>
31 # include <dirent.h>
32 # include <fcntl.h>
33 # include <ctype.h>
34 # include <assert.h>
35 # define bb_dev_null "/dev/null"
36 # define DEFAULT_SHELL "/proc/self/exe"
37 # define bb_banner "busybox standalone"
38 # define ENABLE_FEATURE_SH_STANDALONE 0
39 # define bb_msg_memory_exhausted "memory exhausted"
40 # define xmalloc(size) malloc(size)
41 # define msh_main(argc,argv) main(argc,argv)
42 # define safe_read(fd,buf,count) read(fd,buf,count)
43 # define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
44 # define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
45 # define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
46 # define NORETURN __attribute__ ((__noreturn__))
47 static int find_applet_by_name(const char *applet)
48 {
49         return -1;
50 }
51 static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
52 {
53         unsigned i, out, res;
54         assert(sizeof(unsigned) == 4);
55         if (buflen) {
56                 out = 0;
57                 for (i = 1000000000; i; i /= 10) {
58                         res = n / i;
59                         if (res || out || i == 1) {
60                                 if (!--buflen) break;
61                                 out++;
62                                 n -= res*i;
63                                 *buf++ = '0' + res;
64                         }
65                 }
66         }
67         return buf;
68 }
69 static char *itoa_to_buf(int n, char *buf, unsigned buflen)
70 {
71         if (buflen && n < 0) {
72                 n = -n;
73                 *buf++ = '-';
74                 buflen--;
75         }
76         return utoa_to_buf((unsigned)n, buf, buflen);
77 }
78 static char local_buf[12];
79 static char *itoa(int n)
80 {
81         *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
82         return local_buf;
83 }
84 #else
85 # include "busybox.h" /* for applet_names */
86 #endif
87
88 //#define MSHDEBUG 4
89
90 #ifdef MSHDEBUG
91 static int mshdbg = MSHDEBUG;
92
93 #define DBGPRINTF(x)    if (mshdbg > 0) printf x
94 #define DBGPRINTF0(x)   if (mshdbg > 0) printf x
95 #define DBGPRINTF1(x)   if (mshdbg > 1) printf x
96 #define DBGPRINTF2(x)   if (mshdbg > 2) printf x
97 #define DBGPRINTF3(x)   if (mshdbg > 3) printf x
98 #define DBGPRINTF4(x)   if (mshdbg > 4) printf x
99 #define DBGPRINTF5(x)   if (mshdbg > 5) printf x
100 #define DBGPRINTF6(x)   if (mshdbg > 6) printf x
101 #define DBGPRINTF7(x)   if (mshdbg > 7) printf x
102 #define DBGPRINTF8(x)   if (mshdbg > 8) printf x
103 #define DBGPRINTF9(x)   if (mshdbg > 9) printf x
104
105 static int mshdbg_rc = 0;
106
107 #define RCPRINTF(x)     if (mshdbg_rc) printf x
108
109 #else
110
111 #define DBGPRINTF(x)
112 #define DBGPRINTF0(x) ((void)0)
113 #define DBGPRINTF1(x) ((void)0)
114 #define DBGPRINTF2(x) ((void)0)
115 #define DBGPRINTF3(x) ((void)0)
116 #define DBGPRINTF4(x) ((void)0)
117 #define DBGPRINTF5(x) ((void)0)
118 #define DBGPRINTF6(x) ((void)0)
119 #define DBGPRINTF7(x) ((void)0)
120 #define DBGPRINTF8(x) ((void)0)
121 #define DBGPRINTF9(x) ((void)0)
122
123 #define RCPRINTF(x) ((void)0)
124
125 #endif  /* MSHDEBUG */
126
127
128 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
129 # define DEFAULT_ROOT_PROMPT "\\u:\\w> "
130 # define DEFAULT_USER_PROMPT "\\u:\\w$ "
131 #else
132 # define DEFAULT_ROOT_PROMPT "# "
133 # define DEFAULT_USER_PROMPT "$ "
134 #endif
135
136
137 /* -------- sh.h -------- */
138 /*
139  * shell
140  */
141
142 #define LINELIM   2100
143 #define NPUSH     8             /* limit to input nesting */
144
145 #undef NOFILE
146 #define NOFILE    20            /* Number of open files */
147 #define NUFILE    10            /* Number of user-accessible files */
148 #define FDBASE    10            /* First file usable by Shell */
149
150 /*
151  * values returned by wait
152  */
153 #define WAITSIG(s)  ((s) & 0177)
154 #define WAITVAL(s)  (((s) >> 8) & 0377)
155 #define WAITCORE(s) (((s) & 0200) != 0)
156
157 /*
158  * library and system definitions
159  */
160 typedef void xint;              /* base type of jmp_buf, for not broken compilers */
161
162 /*
163  * shell components
164  */
165 #define NOBLOCK ((struct op *)NULL)
166 #define NOWORD  ((char *)NULL)
167 #define NOWORDS ((char **)NULL)
168 #define NOPIPE  ((int *)NULL)
169
170 /*
171  * redirection
172  */
173 struct ioword {
174         smallint io_flag;               /* action (below) */
175         int io_fd;                      /* fd affected */
176         char *io_name;                  /* file name */
177 };
178
179 #define IOREAD   1                      /* < */
180 #define IOHERE   2                      /* << (here file) */
181 #define IOWRITE  4                      /* > */
182 #define IOCAT    8                      /* >> */
183 #define IOXHERE  16                     /* ${}, ` in << */
184 #define IODUP    32                     /* >&digit */
185 #define IOCLOSE  64                     /* >&- */
186
187 #define IODEFAULT (-1)                  /* "default" IO fd */
188
189
190 /*
191  * Description of a command or an operation on commands.
192  * Might eventually use a union.
193  */
194 struct op {
195         smallint op_type;               /* operation type, see Txxxx below */
196         char **op_words;                /* arguments to a command */
197         struct ioword **ioact;          /* IO actions (eg, < > >>) */
198         struct op *left;
199         struct op *right;
200         char *str;                      /* identifier for case and for */
201 };
202
203 #define TCOM    1       /* command */
204 #define TPAREN  2       /* (c-list) */
205 #define TPIPE   3       /* a | b */
206 #define TLIST   4       /* a [&;] b */
207 #define TOR     5       /* || */
208 #define TAND    6       /* && */
209 #define TFOR    7
210 #define TDO     8
211 #define TCASE   9
212 #define TIF     10
213 #define TWHILE  11
214 #define TUNTIL  12
215 #define TELIF   13
216 #define TPAT    14      /* pattern in case */
217 #define TBRACE  15      /* {c-list} */
218 #define TASYNC  16      /* c & */
219 /* Added to support "." file expansion */
220 #define TDOT    17
221
222 /* Strings for names to make debug easier */
223 #ifdef MSHDEBUG
224 static const char *const T_CMD_NAMES[] = {
225         "PLACEHOLDER",
226         "TCOM",
227         "TPAREN",
228         "TPIPE",
229         "TLIST",
230         "TOR",
231         "TAND",
232         "TFOR",
233         "TDO",
234         "TCASE",
235         "TIF",
236         "TWHILE",
237         "TUNTIL",
238         "TELIF",
239         "TPAT",
240         "TBRACE",
241         "TASYNC",
242         "TDOT",
243 };
244 #endif
245
246 #define AREASIZE (90000)
247
248 /*
249  * flags to control evaluation of words
250  */
251 #define DOSUB    1      /* interpret $, `, and quotes */
252 #define DOBLANK  2      /* perform blank interpretation */
253 #define DOGLOB   4      /* interpret [?* */
254 #define DOKEY    8      /* move words with `=' to 2nd arg. list */
255 #define DOTRIM   16     /* trim resulting string */
256
257 #define DOALL    (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
258
259
260 struct brkcon {
261         jmp_buf brkpt;
262         struct brkcon *nextlev;
263 };
264
265
266 static smallint trapset;                        /* trap pending (signal number) */
267
268 static smallint yynerrs;                        /* yacc (flag) */
269
270 /* moved to G: static char line[LINELIM]; */
271
272 #if ENABLE_FEATURE_EDITING
273 static char *current_prompt;
274 static line_input_t *line_input_state;
275 #endif
276
277
278 /*
279  * other functions
280  */
281 static const char *rexecve(char *c, char **v, char **envp);
282 static char *evalstr(char *cp, int f);
283 static char *putn(int n);
284 static char *unquote(char *as);
285 static int rlookup(char *n);
286 static struct wdblock *glob(char *cp, struct wdblock *wb);
287 static int my_getc(int ec);
288 static int subgetc(char ec, int quoted);
289 static char **makenv(int all, struct wdblock *wb);
290 static char **eval(char **ap, int f);
291 static int setstatus(int s);
292 static int waitfor(int lastpid, int canintr);
293
294 static void onintr(int s);              /* SIGINT handler */
295
296 static int newenv(int f);
297 static void quitenv(void);
298 static void next(int f);
299 static void setdash(void);
300 static void onecommand(void);
301 static void runtrap(int i);
302
303
304 /* -------- area stuff -------- */
305
306 #define REGSIZE   sizeof(struct region)
307 #define GROWBY    (256)
308 /* #define SHRINKBY (64) */
309 #undef  SHRINKBY
310 #define FREE      (32767)
311 #define BUSY      (0)
312 #define ALIGN     (sizeof(int)-1)
313
314
315 struct region {
316         struct region *next;
317         int area;
318 };
319
320
321 /* -------- grammar stuff -------- */
322 typedef union {
323         char *cp;
324         char **wp;
325         int i;
326         struct op *o;
327 } YYSTYPE;
328
329 #define WORD    256
330 #define LOGAND  257
331 #define LOGOR   258
332 #define BREAK   259
333 #define IF      260
334 #define THEN    261
335 #define ELSE    262
336 #define ELIF    263
337 #define FI      264
338 #define CASE    265
339 #define ESAC    266
340 #define FOR     267
341 #define WHILE   268
342 #define UNTIL   269
343 #define DO      270
344 #define DONE    271
345 #define IN      272
346 /* Added for "." file expansion */
347 #define DOT     273
348
349 #define YYERRCODE 300
350
351 /* flags to yylex */
352 #define CONTIN 01     /* skip new lines to complete command */
353
354 static struct op *pipeline(int cf);
355 static struct op *andor(void);
356 static struct op *c_list(void);
357 static int synio(int cf);
358 static void musthave(int c, int cf);
359 static struct op *simple(void);
360 static struct op *nested(int type, int mark);
361 static struct op *command(int cf);
362 static struct op *dogroup(int onlydone);
363 static struct op *thenpart(void);
364 static struct op *elsepart(void);
365 static struct op *caselist(void);
366 static struct op *casepart(void);
367 static char **pattern(void);
368 static char **wordlist(void);
369 static struct op *list(struct op *t1, struct op *t2);
370 static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
371 static struct op *newtp(void);
372 static struct op *namelist(struct op *t);
373 static char **copyw(void);
374 static void word(char *cp);
375 static struct ioword **copyio(void);
376 static struct ioword *io(int u, int f, char *cp);
377 static int yylex(int cf);
378 static int collect(int c, int c1);
379 static int dual(int c);
380 static void diag(int ec);
381 static char *tree(unsigned size);
382
383 /* -------- var.h -------- */
384
385 struct var {
386         char *value;
387         char *name;
388         struct var *next;
389         char status;
390 };
391
392 #define COPYV   1                               /* flag to setval, suggesting copy */
393 #define RONLY   01                              /* variable is read-only */
394 #define EXPORT  02                              /* variable is to be exported */
395 #define GETCELL 04                              /* name & value space was got with getcell */
396
397 static int yyparse(void);
398
399
400 /* -------- io.h -------- */
401 /* io buffer */
402 struct iobuf {
403         unsigned id;            /* buffer id */
404         char buf[512];          /* buffer */
405         char *bufp;             /* pointer into buffer */
406         char *ebufp;            /* pointer to end of buffer */
407 };
408
409 /* possible arguments to an IO function */
410 struct ioarg {
411         const char *aword;
412         char **awordlist;
413         int afile;              /* file descriptor */
414         unsigned afid;          /* buffer id */
415         off_t afpos;            /* file position */
416         struct iobuf *afbuf;    /* buffer for this file */
417 };
418
419 /* an input generator's state */
420 struct io {
421         int (*iofn) (struct ioarg *, struct io *);
422         struct ioarg *argp;
423         int peekc;
424         char prev;              /* previous character read by readc() */
425         char nlcount;           /* for `'s */
426         char xchar;             /* for `'s */
427         char task;              /* reason for pushed IO */
428 };
429 /* ->task: */
430 #define XOTHER  0       /* none of the below */
431 #define XDOLL   1       /* expanding ${} */
432 #define XGRAVE  2       /* expanding `'s */
433 #define XIO     3       /* file IO */
434
435
436 /*
437  * input generators for IO structure
438  */
439 static int nlchar(struct ioarg *ap);
440 static int strchar(struct ioarg *ap);
441 static int qstrchar(struct ioarg *ap);
442 static int filechar(struct ioarg *ap);
443 static int herechar(struct ioarg *ap);
444 static int linechar(struct ioarg *ap);
445 static int gravechar(struct ioarg *ap, struct io *iop);
446 static int qgravechar(struct ioarg *ap, struct io *iop);
447 static int dolchar(struct ioarg *ap);
448 static int wdchar(struct ioarg *ap);
449 static void scraphere(void);
450 static void freehere(int area);
451 static void gethere(void);
452 static void markhere(char *s, struct ioword *iop);
453 static int herein(char *hname, int xdoll);
454 static int run(struct ioarg *argp, int (*f) (struct ioarg *));
455
456
457 static int eofc(void);
458 static int readc(void);
459 static void unget(int c);
460 static void ioecho(char c);
461
462
463 /*
464  * IO control
465  */
466 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
467 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg, (gen)))
468 static int remap(int fd);
469 static int openpipe(int *pv);
470 static void closepipe(int *pv);
471 static struct io *setbase(struct io *ip);
472
473 /* -------- word.h -------- */
474
475 #define NSTART  16                              /* default number of words to allow for initially */
476
477 struct wdblock {
478         short w_bsize;
479         short w_nword;
480         /* bounds are arbitrary */
481         char *w_words[1];
482 };
483
484 static struct wdblock *addword(char *wd, struct wdblock *wb);
485 static struct wdblock *newword(int nw);
486 static char **getwords(struct wdblock *wb);
487
488 /* -------- misc stuff -------- */
489
490 static int dolabel(struct op *t, char **args);
491 static int dohelp(struct op *t, char **args);
492 static int dochdir(struct op *t, char **args);
493 static int doshift(struct op *t, char **args);
494 static int dologin(struct op *t, char **args);
495 static int doumask(struct op *t, char **args);
496 static int doexec(struct op *t, char **args);
497 static int dodot(struct op *t, char **args);
498 static int dowait(struct op *t, char **args);
499 static int doread(struct op *t, char **args);
500 static int doeval(struct op *t, char **args);
501 static int dotrap(struct op *t, char **args);
502 static int dobreak(struct op *t, char **args);
503 static int doexit(struct op *t, char **args);
504 static int doexport(struct op *t, char **args);
505 static int doreadonly(struct op *t, char **args);
506 static int doset(struct op *t, char **args);
507 static int dotimes(struct op *t, char **args);
508 static int docontinue(struct op *t, char **args);
509
510 static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
511 static int execute(struct op *t, int *pin, int *pout, int no_fork);
512 static int iosetup(struct ioword *iop, int pipein, int pipeout);
513 static void brkset(struct brkcon *bc);
514 static int getsig(char *s);
515 static void setsig(int n, sighandler_t f);
516 static int getn(char *as);
517 static int brkcontin(char *cp, int val);
518 static void rdexp(char **wp, void (*f) (struct var *), int key);
519 static void badid(char *s);
520 static void varput(char *s, int out);
521 static int expand(const char *cp, struct wdblock **wbp, int f);
522 static char *blank(int f);
523 static int dollar(int quoted);
524 static int grave(int quoted);
525 static void globname(char *we, char *pp);
526 static char *generate(char *start1, char *end1, char *middle, char *end);
527 static int anyspcl(struct wdblock *wb);
528 static void readhere(char **name, char *s, int ec);
529 static int xxchar(struct ioarg *ap);
530
531 struct here {
532         char *h_tag;
533         char h_dosub;
534         struct ioword *h_iop;
535         struct here *h_next;
536 };
537
538 static const char *const signame[] = {
539         "Signal 0",
540         "Hangup",
541         NULL,  /* interrupt */
542         "Quit",
543         "Illegal instruction",
544         "Trace/BPT trap",
545         "Abort",
546         "Bus error",
547         "Floating Point Exception",
548         "Killed",
549         "SIGUSR1",
550         "SIGSEGV",
551         "SIGUSR2",
552         NULL,  /* broken pipe */
553         "Alarm clock",
554         "Terminated"
555 };
556
557
558 typedef int (*builtin_func_ptr)(struct op *, char **);
559
560 struct builtincmd {
561         const char *name;
562         builtin_func_ptr builtinfunc;
563 };
564
565 static const struct builtincmd builtincmds[] = {
566         { "."       , dodot      },
567         { ":"       , dolabel    },
568         { "break"   , dobreak    },
569         { "cd"      , dochdir    },
570         { "continue", docontinue },
571         { "eval"    , doeval     },
572         { "exec"    , doexec     },
573         { "exit"    , doexit     },
574         { "export"  , doexport   },
575         { "help"    , dohelp     },
576         { "login"   , dologin    },
577         { "newgrp"  , dologin    },
578         { "read"    , doread     },
579         { "readonly", doreadonly },
580         { "set"     , doset      },
581         { "shift"   , doshift    },
582         { "times"   , dotimes    },
583         { "trap"    , dotrap     },
584         { "umask"   , doumask    },
585         { "wait"    , dowait     },
586         { NULL      , NULL       },
587 };
588
589 static struct op *dowholefile(int /*, int*/);
590
591
592 /* Globals */
593 static char **dolv;
594 static int dolc;
595 static uint8_t exstat;
596 static smallint gflg;                   /* (seems to be a parse error indicator) */
597 static smallint interactive;            /* Is this an interactive shell */
598 static smallint execflg;
599 static smallint isbreak;                /* "break" statement was seen */
600 static int multiline;                   /* '\n' changed to ';' (counter) */
601 static struct op *outtree;              /* result from parser */
602 static xint *failpt;
603 static xint *errpt;
604 static struct brkcon *brklist;
605 static struct wdblock *wdlist;
606 static struct wdblock *iolist;
607
608 #ifdef MSHDEBUG
609 static struct var *mshdbg_var;
610 #endif
611 static struct var *vlist;               /* dictionary */
612 static struct var *homedir;             /* home directory */
613 static struct var *prompt;              /* main prompt */
614 static struct var *cprompt;             /* continuation prompt */
615 static struct var *path;                /* search path for commands */
616 static struct var *shell;               /* shell to interpret command files */
617 static struct var *ifs;                 /* field separators */
618
619 static int areanum;                     /* current allocation area */
620 static smallint intr;                   /* interrupt pending (bool) */
621 static smallint heedint = 1;            /* heed interrupt signals (bool) */
622 static int inparse;
623 static char *null = (char*)"";          /* null value for variable */
624 static void (*qflag)(int) = SIG_IGN;
625 static int startl;
626 static int peeksym;
627 static int nlseen;
628 static int iounit = IODEFAULT;
629 static YYSTYPE yylval;
630 static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
631
632 static struct here *inhere;     /* list of hear docs while parsing */
633 static struct here *acthere;    /* list of active here documents */
634 static struct region *areabot;  /* bottom of area */
635 static struct region *areatop;  /* top of area */
636 static struct region *areanxt;  /* starting point of scan */
637 static void *brktop;
638 static void *brkaddr;
639
640 #define AFID_NOBUF      (~0)
641 #define AFID_ID         0
642
643
644 /*
645  * parsing & execution environment
646  */
647 struct env {
648         char *linep;
649         struct io *iobase;
650         struct io *iop;
651         xint *errpt;            /* void * */
652         int iofd;
653         struct env *oenv;
654 };
655
656
657 struct globals {
658         struct env global_env;
659         struct ioarg temparg; // = { .afid = AFID_NOBUF };      /* temporary for PUSHIO */
660         unsigned bufid; // = AFID_ID;   /* buffer id counter */
661         char ourtrap[_NSIG + 1];
662         char *trap[_NSIG + 1];
663         struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
664         struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
665         struct ioarg ioargstack[NPUSH];
666         /*
667          * flags:
668          * -e: quit on error
669          * -k: look for name=value everywhere on command line
670          * -n: no execution
671          * -t: exit after reading and executing one command
672          * -v: echo as read
673          * -x: trace
674          * -u: unset variables net diagnostic
675          */
676         char flags['z' - 'a' + 1];
677         char filechar_cmdbuf[BUFSIZ];
678         char line[LINELIM];
679         char child_cmd[LINELIM];
680
681         struct io iostack[NPUSH];
682
683         char grave__var_name[LINELIM];
684         char grave__alt_value[LINELIM];
685 };
686
687 #define G (*ptr_to_globals)
688 #define global_env      (G.global_env     )
689 #define temparg         (G.temparg        )
690 #define bufid           (G.bufid          )
691 #define ourtrap         (G.ourtrap        )
692 #define trap            (G.trap           )
693 #define sharedbuf       (G.sharedbuf      )
694 #define mainbuf         (G.mainbuf        )
695 #define ioargstack      (G.ioargstack     )
696 /* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
697 #define FLAG            (G.flags - 'a'    )
698 #define filechar_cmdbuf (G.filechar_cmdbuf)
699 #define line            (G.line           )
700 #define child_cmd       (G.child_cmd      )
701 #define iostack         (G.iostack        )
702 #define INIT_G() do { \
703         SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
704         global_env.linep = line; \
705         global_env.iobase = iostack; \
706         global_env.iop = iostack - 1; \
707         global_env.iofd = FDBASE; \
708         temparg.afid = AFID_NOBUF; \
709         bufid = AFID_ID; \
710 } while (0)
711
712
713 /* in substitution */
714 #define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
715
716 #define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
717
718 #ifdef MSHDEBUG
719 static void print_tree(struct op *head)
720 {
721         if (head == NULL) {
722                 DBGPRINTF(("PRINT_TREE: no tree\n"));
723                 return;
724         }
725
726         DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
727                            head->right));
728
729         if (head->left)
730                 print_tree(head->left);
731
732         if (head->right)
733                 print_tree(head->right);
734 }
735 #endif /* MSHDEBUG */
736
737
738 /*
739  * IO functions
740  */
741 static void prs(const char *s)
742 {
743         if (*s)
744                 xwrite_str(STDERR_FILENO, s);
745 }
746
747 static void prn(unsigned u)
748 {
749         prs(itoa(u));
750 }
751
752 static void echo(char **wp)
753 {
754         int i;
755
756         prs("+");
757         for (i = 0; wp[i]; i++) {
758                 if (i)
759                         prs(" ");
760                 prs(wp[i]);
761         }
762         prs("\n");
763 }
764
765 static void closef(int i)
766 {
767         if (i > 2)
768                 close(i);
769 }
770
771 static void closeall(void)
772 {
773         int u;
774
775         for (u = NUFILE; u < NOFILE;)
776                 close(u++);
777 }
778
779
780 /* fail but return to process next command */
781 static void fail(void) NORETURN;
782 static void fail(void)
783 {
784         longjmp(failpt, 1);
785         /* NOTREACHED */
786 }
787
788 /* abort shell (or fail in subshell) */
789 static void leave(void) NORETURN;
790 static void leave(void)
791 {
792         DBGPRINTF(("LEAVE: leave called!\n"));
793
794         if (execflg)
795                 fail();
796         scraphere();
797         freehere(1);
798         runtrap(0);
799         _exit(exstat);
800         /* NOTREACHED */
801 }
802
803 static void warn(const char *s)
804 {
805         if (*s) {
806                 prs(s);
807                 if (!exstat)
808                         exstat = 255;
809         }
810         prs("\n");
811         if (FLAG['e'])
812                 leave();
813 }
814
815 static void err(const char *s)
816 {
817         warn(s);
818         if (FLAG['n'])
819                 return;
820         if (!interactive)
821                 leave();
822         if (global_env.errpt)
823                 longjmp(global_env.errpt, 1);
824         closeall();
825         global_env.iop = global_env.iobase = iostack;
826 }
827
828
829 /* -------- area.c -------- */
830
831 /*
832  * All memory between (char *)areabot and (char *)(areatop+1) is
833  * exclusively administered by the area management routines.
834  * It is assumed that sbrk() and brk() manipulate the high end.
835  */
836
837 #define sbrk(X) ({ \
838         void * __q = (void *)-1; \
839         if (brkaddr + (int)(X) < brktop) { \
840                 __q = brkaddr; \
841                 brkaddr += (int)(X); \
842         } \
843         __q; \
844 })
845
846 static void initarea(void)
847 {
848         brkaddr = xmalloc(AREASIZE);
849         brktop = brkaddr + AREASIZE;
850
851         while ((long) sbrk(0) & ALIGN)
852                 sbrk(1);
853         areabot = (struct region *) sbrk(REGSIZE);
854
855         areabot->next = areabot;
856         areabot->area = BUSY;
857         areatop = areabot;
858         areanxt = areabot;
859 }
860
861 static char *getcell(unsigned nbytes)
862 {
863         int nregio;
864         struct region *p, *q;
865         int i;
866
867         if (nbytes == 0) {
868                 puts("getcell(0)");
869                 abort();
870         }
871         /* silly and defeats the algorithm */
872         /*
873          * round upwards and add administration area
874          */
875         nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
876         p = areanxt;
877         for (;;) {
878                 if (p->area > areanum) {
879                         /*
880                          * merge free cells
881                          */
882                         while ((q = p->next)->area > areanum && q != areanxt)
883                                 p->next = q->next;
884                         /*
885                          * exit loop if cell big enough
886                          */
887                         if (q >= p + nregio)
888                                 goto found;
889                 }
890                 p = p->next;
891                 if (p == areanxt)
892                         break;
893         }
894         i = nregio >= GROWBY ? nregio : GROWBY;
895         p = (struct region *) sbrk(i * REGSIZE);
896         if (p == (struct region *) -1)
897                 return NULL;
898         p--;
899         if (p != areatop) {
900                 puts("not contig");
901                 abort();                                /* allocated areas are contiguous */
902         }
903         q = p + i;
904         p->next = q;
905         p->area = FREE;
906         q->next = areabot;
907         q->area = BUSY;
908         areatop = q;
909  found:
910         /*
911          * we found a FREE area big enough, pointed to by 'p', and up to 'q'
912          */
913         areanxt = p + nregio;
914         if (areanxt < q) {
915                 /*
916                  * split into requested area and rest
917                  */
918                 if (areanxt + 1 > q) {
919                         puts("OOM");
920                         abort();                        /* insufficient space left for admin */
921                 }
922                 areanxt->next = q;
923                 areanxt->area = FREE;
924                 p->next = areanxt;
925         }
926         p->area = areanum;
927         return (char *) (p + 1);
928 }
929
930 static void freecell(char *cp)
931 {
932         struct region *p;
933
934         p = (struct region *) cp;
935         if (p != NULL) {
936                 p--;
937                 if (p < areanxt)
938                         areanxt = p;
939                 p->area = FREE;
940         }
941 }
942 #define DELETE(obj) freecell((char *)obj)
943
944 static void freearea(int a)
945 {
946         struct region *p, *top;
947
948         top = areatop;
949         for (p = areabot; p != top; p = p->next)
950                 if (p->area >= a)
951                         p->area = FREE;
952 }
953
954 static void setarea(char *cp, int a)
955 {
956         struct region *p;
957
958         p = (struct region *) cp;
959         if (p != NULL)
960                 (p - 1)->area = a;
961 }
962
963 static int getarea(char *cp)
964 {
965         return ((struct region *) cp - 1)->area;
966 }
967
968 static void garbage(void)
969 {
970         struct region *p, *q, *top;
971
972         top = areatop;
973         for (p = areabot; p != top; p = p->next) {
974                 if (p->area > areanum) {
975                         while ((q = p->next)->area > areanum)
976                                 p->next = q->next;
977                         areanxt = p;
978                 }
979         }
980 #ifdef SHRINKBY
981         if (areatop >= q + SHRINKBY && q->area > areanum) {
982                 brk((char *) (q + 1));
983                 q->next = areabot;
984                 q->area = BUSY;
985                 areatop = q;
986         }
987 #endif
988 }
989
990 static void *get_space(int n)
991 {
992         char *cp;
993
994         cp = getcell(n);
995         if (cp == NULL)
996                 err("out of string space");
997         return cp;
998 }
999
1000 static char *strsave(const char *s, int a)
1001 {
1002         char *cp;
1003
1004         cp = get_space(strlen(s) + 1);
1005         if (cp == NULL) {
1006 // FIXME: I highly doubt this is good.
1007                 return (char*)"";
1008         }
1009         setarea(cp, a);
1010         strcpy(cp, s);
1011         return cp;
1012 }
1013
1014
1015 /* -------- var.c -------- */
1016
1017 static int eqname(const char *n1, const char *n2)
1018 {
1019         for (; *n1 != '=' && *n1 != '\0'; n1++)
1020                 if (*n2++ != *n1)
1021                         return 0;
1022         return *n2 == '\0' || *n2 == '=';
1023 }
1024
1025 static const char *findeq(const char *cp)
1026 {
1027         while (*cp != '\0' && *cp != '=')
1028                 cp++;
1029         return cp;
1030 }
1031
1032 /*
1033  * Find the given name in the dictionary
1034  * and return its value.  If the name was
1035  * not previously there, enter it now and
1036  * return a null value.
1037  */
1038 static struct var *lookup(const char *n)
1039 {
1040 // FIXME: dirty hack
1041         static struct var dummy;
1042
1043         struct var *vp;
1044         const char *cp;
1045         char *xp;
1046         int c;
1047
1048         if (isdigit(*n)) {
1049                 dummy.name = (char*)n;
1050                 for (c = 0; isdigit(*n) && c < 1000; n++)
1051                         c = c * 10 + *n - '0';
1052                 dummy.status = RONLY;
1053                 dummy.value = (c <= dolc ? dolv[c] : null);
1054                 return &dummy;
1055         }
1056
1057         for (vp = vlist; vp; vp = vp->next)
1058                 if (eqname(vp->name, n))
1059                         return vp;
1060
1061         cp = findeq(n);
1062         vp = get_space(sizeof(*vp));
1063         if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
1064                 dummy.name = dummy.value = (char*)"";
1065                 return &dummy;
1066         }
1067
1068         xp = vp->name;
1069         while ((*xp = *n++) != '\0' && *xp != '=')
1070                 xp++;
1071         *xp++ = '=';
1072         *xp = '\0';
1073         setarea((char *) vp, 0);
1074         setarea((char *) vp->name, 0);
1075         vp->value = null;
1076         vp->next = vlist;
1077         vp->status = GETCELL;
1078         vlist = vp;
1079         return vp;
1080 }
1081
1082 /*
1083  * if name is not NULL, it must be
1084  * a prefix of the space `val',
1085  * and end with `='.
1086  * this is all so that exporting
1087  * values is reasonably painless.
1088  */
1089 static void nameval(struct var *vp, const char *val, const char *name)
1090 {
1091         const char *cp;
1092         char *xp;
1093         int fl;
1094
1095         if (vp->status & RONLY) {
1096                 xp = vp->name;
1097                 while (*xp && *xp != '=')
1098                         fputc(*xp++, stderr);
1099                 err(" is read-only");
1100                 return;
1101         }
1102         fl = 0;
1103         if (name == NULL) {
1104                 xp = get_space(strlen(vp->name) + strlen(val) + 2);
1105                 if (xp == NULL)
1106                         return;
1107                 /* make string: name=value */
1108                 setarea(xp, 0);
1109                 name = xp;
1110                 cp = vp->name;
1111                 while ((*xp = *cp++) != '\0' && *xp != '=')
1112                         xp++;
1113                 *xp++ = '=';
1114                 strcpy(xp, val);
1115                 val = xp;
1116                 fl = GETCELL;
1117         }
1118         if (vp->status & GETCELL)
1119                 freecell(vp->name);             /* form new string `name=value' */
1120         vp->name = (char*)name;
1121         vp->value = (char*)val;
1122         vp->status |= fl;
1123 }
1124
1125 /*
1126  * give variable at `vp' the value `val'.
1127  */
1128 static void setval(struct var *vp, const char *val)
1129 {
1130         nameval(vp, val, NULL);
1131 }
1132
1133 static void export(struct var *vp)
1134 {
1135         vp->status |= EXPORT;
1136 }
1137
1138 static void ronly(struct var *vp)
1139 {
1140         if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1141                 vp->status |= RONLY;
1142 }
1143
1144 static int isassign(const char *s)
1145 {
1146         unsigned char c;
1147         DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1148
1149         c = *s;
1150         /* no isalpha() - we shouldn't use locale */
1151         /* c | 0x20 - lowercase (Latin) letters */
1152         if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1153                 /* not letter */
1154                 return 0;
1155
1156         while (1) {
1157                 c = *++s;
1158                 if (c == '=')
1159                         return 1;
1160                 if (c == '\0')
1161                         return 0;
1162                 if (c != '_'
1163                  && (unsigned)(c - '0') > 9  /* not number */
1164                  && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
1165                 ) {
1166                         return 0;
1167                 }
1168         }
1169 }
1170
1171 static int assign(const char *s, int cf)
1172 {
1173         const char *cp;
1174         struct var *vp;
1175
1176         DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1177
1178         if (!isalpha(*s) && *s != '_')
1179                 return 0;
1180         for (cp = s; *cp != '='; cp++)
1181                 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1182                         return 0;
1183         vp = lookup(s);
1184         nameval(vp, ++cp, cf == COPYV ? NULL : s);
1185         if (cf != COPYV)
1186                 vp->status &= ~GETCELL;
1187         return 1;
1188 }
1189
1190 static int checkname(char *cp)
1191 {
1192         DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1193
1194         if (!isalpha(*cp++) && *(cp - 1) != '_')
1195                 return 0;
1196         while (*cp)
1197                 if (!isalnum(*cp++) && *(cp - 1) != '_')
1198                         return 0;
1199         return 1;
1200 }
1201
1202 static void putvlist(int f, int out)
1203 {
1204         struct var *vp;
1205
1206         for (vp = vlist; vp; vp = vp->next) {
1207                 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1208                         if (vp->status & EXPORT)
1209                                 write(out, "export ", 7);
1210                         if (vp->status & RONLY)
1211                                 write(out, "readonly ", 9);
1212                         write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1213                         write(out, "\n", 1);
1214                 }
1215         }
1216 }
1217
1218
1219 /*
1220  * trap handling
1221  */
1222 static void sig(int i)
1223 {
1224         trapset = i;
1225         signal(i, sig);
1226 }
1227
1228 static void runtrap(int i)
1229 {
1230         char *trapstr;
1231
1232         trapstr = trap[i];
1233         if (trapstr == NULL)
1234                 return;
1235
1236         if (i == 0)
1237                 trap[i] = NULL;
1238
1239         RUN(aword, trapstr, nlchar);
1240 }
1241
1242
1243 static void setdash(void)
1244 {
1245         char *cp;
1246         int c;
1247         char m['z' - 'a' + 1];
1248
1249         cp = m;
1250         for (c = 'a'; c <= 'z'; c++)
1251                 if (FLAG[c])
1252                         *cp++ = c;
1253         *cp = '\0';
1254         setval(lookup("-"), m);
1255 }
1256
1257 static int newfile(char *s)
1258 {
1259         int f;
1260
1261         DBGPRINTF7(("NEWFILE: opening %s\n", s));
1262
1263         f = 0;
1264         if (NOT_LONE_DASH(s)) {
1265                 DBGPRINTF(("NEWFILE: s is %s\n", s));
1266                 f = open(s, O_RDONLY);
1267                 if (f < 0) {
1268                         prs(s);
1269                         err(": can't open");
1270                         return 1;
1271                 }
1272         }
1273
1274         next(remap(f));
1275         return 0;
1276 }
1277
1278
1279 #ifdef UNUSED
1280 struct op *scantree(struct op *head)
1281 {
1282         struct op *dotnode;
1283
1284         if (head == NULL)
1285                 return NULL;
1286
1287         if (head->left != NULL) {
1288                 dotnode = scantree(head->left);
1289                 if (dotnode)
1290                         return dotnode;
1291         }
1292
1293         if (head->right != NULL) {
1294                 dotnode = scantree(head->right);
1295                 if (dotnode)
1296                         return dotnode;
1297         }
1298
1299         if (head->op_words == NULL)
1300                 return NULL;
1301
1302         DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1303
1304         if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
1305                 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1306                 return head;
1307         }
1308
1309         return NULL;
1310 }
1311 #endif
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 = NULL;
1329         iolist = NULL;
1330         global_env.errpt = NULL;
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 UNUSED_PARAM) /* 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) 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) 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->op_type != TPAREN && t->op_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                 }
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->op_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->op_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->op_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->op_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->op_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->op_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->op_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\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->op_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->op_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->op_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->op_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                 { ""     , 0      },
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->op_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->op_type != TCOM) {
2108                 if (t->op_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 = NULL;
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 = NULL;
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_fd = 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->op_type=%d (%s)\n", t->op_type,
2404                                 T_CMD_NAMES[t->op_type]));
2405
2406         if (t->op_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->op_type=%d (%s), t->op_words is %s\n", t,
2462                            t->op_type, T_CMD_NAMES[t->op_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->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
2470                 : NULL;
2471
2472         switch (t->op_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->op_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                 /* Restore areanum value. It may be incremented by execute()
2575                  * below, and then "continue" may jump back to setjmp above */
2576                 areanum = a + 1;
2577                 freearea(areanum + 1);
2578                 brkset(&bc);
2579                 for (t1 = t->left; i-- && *wp != NULL;) {
2580                         setval(vp, *wp++);
2581                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2582                 }
2583                 brklist = brklist->nextlev;
2584                 break;
2585
2586         case TWHILE:
2587         case TUNTIL:
2588                 while (setjmp(bc.brkpt))
2589                         if (isbreak)
2590                                 goto broken;
2591                 /* Restore areanum value. It may be incremented by execute()
2592                  * below, and then "continue" may jump back to setjmp above */
2593                 areanum = a + 1;
2594                 freearea(areanum + 1);
2595                 brkset(&bc);
2596                 t1 = t->left;
2597                 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
2598                         rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2599                 brklist = brklist->nextlev;
2600                 break;
2601
2602         case TIF:
2603         case TELIF:
2604                 if (t->right != NULL) {
2605                         rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2606                                 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2607                                 execute(t->right->right, pin, pout, /* no_fork: */ 0);
2608                 }
2609                 break;
2610
2611         case TCASE:
2612                 cp = evalstr(t->str, DOSUB | DOTRIM);
2613                 if (cp == NULL)
2614                         cp = "";
2615
2616                 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2617                                         ((t->str == NULL) ? "NULL" : t->str),
2618                                         ((cp == NULL) ? "NULL" : cp)));
2619
2620                 t1 = findcase(t->left, cp);
2621                 if (t1 != NULL) {
2622                         DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2623                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2624                         DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2625                 }
2626                 break;
2627
2628         case TBRACE:
2629 /*
2630                 iopp = t->ioact;
2631                 if (i)
2632                         while (*iopp)
2633                                 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2634                                         rv = -1;
2635                                         break;
2636                                 }
2637 */
2638                 if (rv >= 0) {
2639                         t1 = t->left;
2640                         if (t1) {
2641                                 rv = execute(t1, pin, pout, /* no_fork: */ 0);
2642                         }
2643                 }
2644                 break;
2645
2646         };
2647
2648  broken:
2649 // Restoring op_words is most likely not needed now: see comment in forkexec()
2650 // (also take a look at exec builtin (doexec) - it touches t->op_words)
2651         t->op_words = wp2;
2652         isbreak = 0;
2653         freehere(areanum);
2654         freearea(areanum);
2655         areanum = a;
2656         if (interactive && intr) {
2657                 closeall();
2658                 fail();
2659         }
2660
2661         i = trapset;
2662         if (i != 0) {
2663                 trapset = 0;
2664                 runtrap(i);
2665         }
2666
2667         DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2668         return rv;
2669 }
2670
2671 static builtin_func_ptr inbuilt(const char *s)
2672 {
2673         const struct builtincmd *bp;
2674
2675         for (bp = builtincmds; bp->name; bp++)
2676                 if (strcmp(bp->name, s) == 0)
2677                         return bp->builtinfunc;
2678         return NULL;
2679 }
2680
2681 static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
2682 {
2683         pid_t newpid;
2684         int i;
2685         builtin_func_ptr bltin = NULL;
2686         const char *bltin_name = NULL;
2687         const char *cp;
2688         struct ioword **iopp;
2689         int resetsig;
2690         char **owp;
2691         int forked;
2692
2693         int *hpin = pin;
2694         int *hpout = pout;
2695         char *hwp;
2696         smallint hinteractive;
2697         smallint hintr;
2698         smallint hexecflg;
2699         struct brkcon *hbrklist;
2700
2701 #if __GNUC__
2702         /* Avoid longjmp clobbering */
2703         (void) &pin;
2704         (void) &pout;
2705         (void) &wp;
2706         (void) &bltin;
2707         (void) &cp;
2708         (void) &resetsig;
2709         (void) &owp;
2710 #endif
2711
2712         DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2713                         pout, no_fork));
2714         DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2715                         ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
2716         owp = wp;
2717         resetsig = 0;
2718         if (t->op_type == TCOM) {
2719                 while (*wp++ != NULL)
2720                         continue;
2721                 cp = *wp;
2722
2723                 /* strip all initial assignments */
2724                 /* FIXME: not correct wrt PATH=yyy command etc */
2725                 if (FLAG['x']) {
2726                         DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2727                                                 cp, wp, owp));
2728                         echo(cp ? wp : owp);
2729                 }
2730
2731                 if (cp == NULL) {
2732                         if (t->ioact == NULL) {
2733                                 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2734                                         continue;
2735                                 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2736                                 return setstatus(0);
2737                         }
2738                 } else { /* cp != NULL */
2739                         bltin_name = cp;
2740                         bltin = inbuilt(cp);
2741                 }
2742         }
2743
2744         forked = 0;
2745         // We were pointing t->op_words to temporary (expanded) arg list:
2746         // t->op_words = wp;
2747         // and restored it later (in execute()), but "break"
2748         // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
2749         // See http://bugs.busybox.net/view.php?id=846.
2750         // Now we do not touch t->op_words, but separately pass wp as param list
2751         // to builtins
2752         DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2753                         no_fork, owp));
2754         /* Don't fork if it is a lone builtin (not in pipe)
2755          * OR we are told to _not_ fork */
2756         if ((!bltin || pin || pout)   /* not lone bltin AND */
2757          && !no_fork                  /* not told to avoid fork */
2758         ) {
2759                 /* Save values in case child alters them after vfork */
2760                 hpin = pin;
2761                 hpout = pout;
2762                 hwp = *wp;
2763                 hinteractive = interactive;
2764                 hintr = intr;
2765                 hbrklist = brklist;
2766                 hexecflg = execflg;
2767
2768                 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2769                 newpid = vfork();
2770                 if (newpid == -1) {
2771                         DBGPRINTF(("FORKEXEC: ERROR, can't vfork()!\n"));
2772                         return -1;
2773                 }
2774
2775                 if (newpid > 0) {  /* Parent */
2776                         /* Restore values */
2777                         pin = hpin;
2778                         pout = hpout;
2779                         *wp = hwp;
2780                         interactive = hinteractive;
2781                         intr = hintr;
2782                         brklist = hbrklist;
2783                         execflg = hexecflg;
2784
2785                         closepipe(pin);
2786                         return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2787                 }
2788
2789                 /* Child */
2790                 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
2791                 if (interactive) {
2792                         signal(SIGINT, SIG_IGN);
2793                         signal(SIGQUIT, SIG_IGN);
2794                         resetsig = 1;
2795                 }
2796                 interactive = 0;
2797                 intr = 0;
2798                 forked = 1;
2799                 brklist = 0;
2800                 execflg = 0;
2801         }
2802
2803         if (owp)
2804                 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2805                         if (!bltin)
2806                                 export(lookup(cp));
2807
2808         if (pin) { /* NB: close _first_, then move fds! */
2809                 close(pin[1]);
2810                 xmove_fd(pin[0], 0);
2811         }
2812         if (pout) {
2813                 close(pout[0]);
2814                 xmove_fd(pout[1], 1);
2815         }
2816
2817         iopp = t->ioact;
2818         if (iopp) {
2819                 if (bltin && bltin != doexec) {
2820                         prs(bltin_name);
2821                         err(": can't redirect shell command");
2822                         if (forked)
2823                                 _exit(-1);
2824                         return -1;
2825                 }
2826                 while (*iopp) {
2827                         if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2828                                 /* system-detected error */
2829                                 if (forked)
2830                                         _exit(-1);
2831                                 return -1;
2832                         }
2833                 }
2834         }
2835
2836         if (bltin) {
2837                 if (forked || pin || pout) {
2838                         /* Builtin in pipe: disallowed */
2839                         /* TODO: allow "exec"? */
2840                         prs(bltin_name);
2841                         err(": can't run builtin as part of pipe");
2842                         if (forked)
2843                                 _exit(-1);
2844                         return -1;
2845                 }
2846                 /* Run builtin */
2847                 i = setstatus(bltin(t, wp));
2848                 if (forked)
2849                         _exit(i);
2850                 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2851                 return i;
2852         }
2853
2854         /* should use FIOCEXCL */
2855         for (i = FDBASE; i < NOFILE; i++)
2856                 close(i);
2857         if (resetsig) {
2858                 signal(SIGINT, SIG_DFL);
2859                 signal(SIGQUIT, SIG_DFL);
2860         }
2861
2862         if (t->op_type == TPAREN)
2863                 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
2864         if (wp[0] == NULL)
2865                 _exit(EXIT_SUCCESS);
2866
2867         cp = rexecve(wp[0], wp, makenv(0, NULL));
2868         prs(wp[0]);
2869         prs(": ");
2870         err(cp);
2871         if (!execflg)
2872                 trap[0] = NULL;
2873
2874         DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
2875
2876         leave();
2877         /* NOTREACHED */
2878         return 0;
2879 }
2880
2881 /*
2882  * 0< 1> are ignored as required
2883  * within pipelines.
2884  */
2885 static int iosetup(struct ioword *iop, int pipein, int pipeout)
2886 {
2887         int u = -1;
2888         char *cp = NULL;
2889         const char *msg;
2890
2891         DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2892                            pipein, pipeout));
2893
2894         if (iop->io_fd == IODEFAULT)    /* take default */
2895                 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2896
2897         if (pipein && iop->io_fd == 0)
2898                 return 0;
2899
2900         if (pipeout && iop->io_fd == 1)
2901                 return 0;
2902
2903         msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2904         if ((iop->io_flag & IOHERE) == 0) {
2905                 cp = iop->io_name; /* huh?? */
2906                 cp = evalstr(cp, DOSUB | DOTRIM);
2907                 if (cp == NULL)
2908                         return 1;
2909         }
2910
2911         if (iop->io_flag & IODUP) {
2912                 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2913                         prs(cp);
2914                         err(": illegal >& argument");
2915                         return 1;
2916                 }
2917                 if (*cp == '-')
2918                         iop->io_flag = IOCLOSE;
2919                 iop->io_flag &= ~(IOREAD | IOWRITE);
2920         }
2921
2922         switch (iop->io_flag) {
2923         case IOREAD:
2924                 u = open(cp, O_RDONLY);
2925                 break;
2926
2927         case IOHERE:
2928         case IOHERE | IOXHERE:
2929                 u = herein(iop->io_name, iop->io_flag & IOXHERE);
2930                 cp = (char*)"here file";
2931                 break;
2932
2933         case IOWRITE | IOCAT:
2934                 u = open(cp, O_WRONLY);
2935                 if (u >= 0) {
2936                         lseek(u, (long) 0, SEEK_END);
2937                         break;
2938                 }
2939                 /* fall through to creation if >>file doesn't exist */
2940
2941         case IOWRITE:
2942                 u = creat(cp, 0666);
2943                 break;
2944
2945         case IODUP:
2946                 u = dup2(*cp - '0', iop->io_fd);
2947                 break;
2948
2949         case IOCLOSE:
2950                 close(iop->io_fd);
2951                 return 0;
2952         }
2953
2954         if (u < 0) {
2955                 prs(cp);
2956                 prs(": can't ");
2957                 warn(msg);
2958                 return 1;
2959         }
2960         xmove_fd(u, iop->io_fd);
2961         return 0;
2962 }
2963
2964 /*
2965  * Enter a new loop level (marked for break/continue).
2966  */
2967 static void brkset(struct brkcon *bc)
2968 {
2969         bc->nextlev = brklist;
2970         brklist = bc;
2971 }
2972
2973 /*
2974  * Wait for the last process created.
2975  * Print a message for each process found
2976  * that was killed by a signal.
2977  * Ignore interrupt signals while waiting
2978  * unless `canintr' is true.
2979  */
2980 static int waitfor(int lastpid, int canintr)
2981 {
2982         int pid, rv;
2983         int s;
2984         smallint oheedint = heedint;
2985
2986         heedint = 0;
2987         rv = 0;
2988         do {
2989                 pid = wait(&s);
2990                 if (pid == -1) {
2991                         if (errno != EINTR || canintr)
2992                                 break;
2993                 } else {
2994                         rv = WAITSIG(s);
2995                         if (rv != 0) {
2996                                 if (rv < ARRAY_SIZE(signame)) {
2997                                         if (signame[rv] != NULL) {
2998                                                 if (pid != lastpid) {
2999                                                         prn(pid);
3000                                                         prs(": ");
3001                                                 }
3002                                                 prs(signame[rv]);
3003                                         }
3004                                 } else {
3005                                         if (pid != lastpid) {
3006                                                 prn(pid);
3007                                                 prs(": ");
3008                                         }
3009                                         prs("Signal ");
3010                                         prn(rv);
3011                                         prs(" ");
3012                                 }
3013                                 if (WAITCORE(s))
3014                                         prs(" - core dumped");
3015                                 if (rv >= ARRAY_SIZE(signame) || signame[rv])
3016                                         prs("\n");
3017                                 rv |= 0x80;
3018                         } else
3019                                 rv = WAITVAL(s);
3020                 }
3021         } while (pid != lastpid);
3022         heedint = oheedint;
3023         if (intr) {
3024                 if (interactive) {
3025                         if (canintr)
3026                                 intr = 0;
3027                 } else {
3028                         if (exstat == 0)
3029                                 exstat = rv;
3030                         onintr(0);
3031                 }
3032         }
3033         return rv;
3034 }
3035
3036 static int setstatus(int s)
3037 {
3038         exstat = s;
3039         setval(lookup("?"), putn(s));
3040         return s;
3041 }
3042
3043 /*
3044  * PATH-searching interface to execve.
3045  * If getenv("PATH") were kept up-to-date,
3046  * execvp might be used.
3047  */
3048 static const char *rexecve(char *c, char **v, char **envp)
3049 {
3050         const char *sp;
3051         char *tp;
3052         int asis = 0;
3053         char *name = c;
3054
3055         if (ENABLE_FEATURE_SH_STANDALONE) {
3056                 if (find_applet_by_name(name) >= 0) {
3057                         /* We have to exec here since we vforked.  Running
3058                          * run_applet_and_exit() won't work and bad things
3059                          * will happen. */
3060                         execve(bb_busybox_exec_path, v, envp);
3061                 }
3062         }
3063
3064         DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3065
3066         sp = any('/', c) ? "" : path->value;
3067         asis = (*sp == '\0');
3068         while (asis || *sp != '\0') {
3069                 asis = 0;
3070                 tp = global_env.linep;
3071                 for (; *sp != '\0'; tp++) {
3072                         *tp = *sp++;
3073                         if (*tp == ':') {
3074                                 asis = (*sp == '\0');
3075                                 break;
3076                         }
3077                 }
3078                 if (tp != global_env.linep)
3079                         *tp++ = '/';
3080                 strcpy(tp, c);
3081
3082                 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
3083
3084                 execve(global_env.linep, v, envp);
3085
3086                 switch (errno) {
3087                 case ENOEXEC:
3088                         /* File is executable but file format isnt recognized */
3089                         /* Run it as a shell script */
3090                         /* (execve above didnt do it itself, unlike execvp) */
3091                         *v = global_env.linep;
3092                         v--;
3093                         tp = *v;
3094                         *v = (char*)DEFAULT_SHELL;
3095                         execve(DEFAULT_SHELL, v, envp);
3096                         *v = tp;
3097                         return "no shell";
3098
3099                 case ENOMEM:
3100                         return (char *) bb_msg_memory_exhausted;
3101
3102                 case E2BIG:
3103                         return "argument list too long";
3104                 }
3105         }
3106         if (errno == ENOENT) {
3107                 exstat = 127; /* standards require this */
3108                 return "not found";
3109         }
3110         exstat = 126; /* mimic bash */
3111         return "can't execute";
3112 }
3113
3114 /*
3115  * Run the command produced by generator `f'
3116  * applied to stream `arg'.
3117  */
3118 static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3119 {
3120         struct op *otree;
3121         struct wdblock *swdlist;
3122         struct wdblock *siolist;
3123         jmp_buf ev, rt;
3124         xint *ofail;
3125         int rv;
3126
3127 #if __GNUC__
3128         /* Avoid longjmp clobbering */
3129         (void) &rv;
3130 #endif
3131
3132         DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3133                            areanum, outtree, failpt));
3134
3135         areanum++;
3136         swdlist = wdlist;
3137         siolist = iolist;
3138         otree = outtree;
3139         ofail = failpt;
3140         rv = -1;
3141
3142         errpt = ev;
3143         if (newenv(setjmp(errpt)) == 0) {
3144                 wdlist = NULL;
3145                 iolist = NULL;
3146                 pushio(argp, f);
3147                 global_env.iobase = global_env.iop;
3148                 yynerrs = 0;
3149                 failpt = rt;
3150                 if (setjmp(failpt) == 0 && yyparse() == 0)
3151                         rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
3152                 quitenv();
3153         } else {
3154                 DBGPRINTF(("RUN: error from newenv()!\n"));
3155         }
3156
3157         wdlist = swdlist;
3158         iolist = siolist;
3159         failpt = ofail;
3160         outtree = otree;
3161         freearea(areanum--);
3162
3163         return rv;
3164 }
3165
3166 /* -------- do.c -------- */
3167
3168 /*
3169  * built-in commands: doX
3170  */
3171
3172 static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3173 {
3174         int col;
3175         const struct builtincmd *x;
3176
3177         printf(
3178                 "Built-in commands:\n"
3179                 "------------------\n");
3180
3181         col = 0;
3182         x = builtincmds;
3183         while (x->name) {
3184                 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
3185                 if (col > 60) {
3186                         bb_putchar('\n');
3187                         col = 0;
3188                 }
3189                 x++;
3190         }
3191 #if ENABLE_FEATURE_SH_STANDALONE
3192         {
3193                 const char *applet = applet_names;
3194
3195                 while (*applet) {
3196                         col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
3197                         if (col > 60) {
3198                                 bb_putchar('\n');
3199                                 col = 0;
3200                         }
3201                         applet += strlen(applet) + 1;
3202                 }
3203         }
3204 #endif
3205         puts("\n");
3206         return EXIT_SUCCESS;
3207 }
3208
3209 static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3210 {
3211         return 0;
3212 }
3213
3214 static int dochdir(struct op *t UNUSED_PARAM, char **args)
3215 {
3216         const char *cp, *er;
3217
3218         cp = args[1];
3219         if (cp == NULL) {
3220                 cp = homedir->value;
3221                 if (cp != NULL)
3222                         goto do_cd;
3223                 er = ": no home directory";
3224         } else {
3225  do_cd:
3226                 if (chdir(cp) >= 0)
3227                         return 0;
3228                 er = ": bad directory";
3229         }
3230         prs(cp != NULL ? cp : "cd");
3231         err(er);
3232         return 1;
3233 }
3234
3235 static int doshift(struct op *t UNUSED_PARAM, char **args)
3236 {
3237         int n;
3238
3239         n = args[1] ? getn(args[1]) : 1;
3240         if (dolc < n) {
3241                 err("nothing to shift");
3242                 return 1;
3243         }
3244         dolv[n] = dolv[0];
3245         dolv += n;
3246         dolc -= n;
3247         setval(lookup("#"), putn(dolc));
3248         return 0;
3249 }
3250
3251 /*
3252  * execute login and newgrp directly
3253  */
3254 static int dologin(struct op *t UNUSED_PARAM, char **args)
3255 {
3256         const char *cp;
3257
3258         if (interactive) {
3259                 signal(SIGINT, SIG_DFL);
3260                 signal(SIGQUIT, SIG_DFL);
3261         }
3262         cp = rexecve(args[0], args, makenv(0, NULL));
3263         prs(args[0]);
3264         prs(": ");
3265         err(cp);
3266         return 1;
3267 }
3268
3269 static int doumask(struct op *t UNUSED_PARAM, char **args)
3270 {
3271         int i;
3272         char *cp;
3273
3274         cp = args[1];
3275         if (cp == NULL) {
3276                 i = umask(0);
3277                 umask(i);
3278                 printf("%04o\n", i);
3279         } else {
3280                 i = bb_strtou(cp, NULL, 8);
3281                 if (errno) {
3282                         err("umask: bad octal number");
3283                         return 1;
3284                 }
3285                 umask(i);
3286         }
3287         return 0;
3288 }
3289
3290 static int doexec(struct op *t, char **args)
3291 {
3292         jmp_buf ex;
3293         xint *ofail;
3294         char **sv_words;
3295
3296         t->ioact = NULL;
3297         if (!args[1])
3298                 return 1;
3299
3300         execflg = 1;
3301         ofail = failpt;
3302         failpt = ex;
3303
3304         sv_words = t->op_words;
3305         t->op_words = args + 1;
3306 // TODO: test what will happen with "exec break" -
3307 // will it leave t->op_words pointing to garbage?
3308 // (see http://bugs.busybox.net/view.php?id=846)
3309         if (setjmp(failpt) == 0)
3310                 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
3311         t->op_words = sv_words;
3312
3313         failpt = ofail;
3314         execflg = 0;
3315
3316         return 1;
3317 }
3318
3319 static int dodot(struct op *t UNUSED_PARAM, char **args)
3320 {
3321         int i;
3322         const char *sp;
3323         char *tp;
3324         char *cp;
3325         int maltmp;
3326
3327         DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3328                 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3329
3330         cp = args[1];
3331         if (cp == NULL) {
3332                 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3333                 return 0;
3334         }
3335         DBGPRINTF(("DODOT: cp is %s\n", cp));
3336
3337         sp = any('/', cp) ? ":" : path->value;
3338
3339         DBGPRINTF(("DODOT: sp is %s,  global_env.linep is %s\n",
3340                            ((sp == NULL) ? "NULL" : sp),
3341                            ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3342
3343         while (*sp) {
3344                 tp = global_env.linep;
3345                 while (*sp && (*tp = *sp++) != ':')
3346                         tp++;
3347                 if (tp != global_env.linep)
3348                         *tp++ = '/';
3349                 strcpy(tp, cp);
3350
3351                 /* Original code */
3352                 i = open(global_env.linep, O_RDONLY);
3353                 if (i >= 0) {
3354                         exstat = 0;
3355                         maltmp = remap(i);
3356                         DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3357                                 maltmp, exstat, global_env.iofd, i, global_env.linep));
3358
3359                         next(maltmp);           /* Basically a PUSHIO */
3360
3361                         DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3362
3363                         return exstat;
3364                 }
3365         } /* while */
3366
3367         prs(cp);
3368         err(": not found");
3369
3370         return -1;
3371 }
3372
3373 static int dowait(struct op *t UNUSED_PARAM, char **args)
3374 {
3375         int i;
3376         char *cp;
3377
3378         cp = args[1];
3379         if (cp != NULL) {
3380                 i = getn(cp);
3381                 if (i == 0)
3382                         return 0;
3383         } else
3384                 i = -1;
3385         setstatus(waitfor(i, 1));
3386         return 0;
3387 }
3388
3389 static int doread(struct op *t UNUSED_PARAM, char **args)
3390 {
3391         char *cp, **wp;
3392         int nb = 0;
3393         int nl = 0;
3394
3395         if (args[1] == NULL) {
3396                 err("Usage: read name ...");
3397                 return 1;
3398         }
3399         for (wp = args + 1; *wp; wp++) {
3400                 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
3401                         nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
3402                         if (nb != sizeof(*cp))
3403                                 break;
3404                         nl = (*cp == '\n');
3405                         if (nl || (wp[1] && any(*cp, ifs->value)))
3406                                 break;
3407                 }
3408                 *cp = '\0';
3409                 if (nb <= 0)
3410                         break;
3411                 setval(lookup(*wp), global_env.linep);
3412         }
3413         return nb <= 0;
3414 }
3415
3416 static int doeval(struct op *t UNUSED_PARAM, char **args)
3417 {
3418         return RUN(awordlist, args + 1, wdchar);
3419 }
3420
3421 static int dotrap(struct op *t UNUSED_PARAM, char **args)
3422 {
3423         int n, i;
3424         int resetsig;
3425
3426         if (args[1] == NULL) {
3427                 for (i = 0; i <= _NSIG; i++)
3428                         if (trap[i]) {
3429                                 prn(i);
3430                                 prs(": ");
3431                                 prs(trap[i]);
3432                                 prs("\n");
3433                         }
3434                 return 0;
3435         }
3436         resetsig = isdigit(args[1][0]);
3437         for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3438                 n = getsig(args[i]);
3439                 freecell(trap[n]);
3440                 trap[n] = 0;
3441                 if (!resetsig) {
3442                         if (args[1][0] != '\0') {
3443                                 trap[n] = strsave(args[1], 0);
3444                                 setsig(n, sig);
3445                         } else
3446                                 setsig(n, SIG_IGN);
3447                 } else {
3448                         if (interactive) {
3449                                 if (n == SIGINT)
3450                                         setsig(n, onintr);
3451                                 else
3452                                         setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3453                         } else
3454                                 setsig(n, SIG_DFL);
3455                 }
3456         }
3457         return 0;
3458 }
3459
3460 static int getsig(char *s)
3461 {
3462         int n;
3463
3464         n = getn(s);
3465         if (n < 0 || n > _NSIG) {
3466                 err("trap: bad signal number");
3467                 n = 0;
3468         }
3469         return n;
3470 }
3471
3472 static void setsig(int n, sighandler_t f)
3473 {
3474         if (n == 0)
3475                 return;
3476         if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3477                 ourtrap[n] = 1;
3478                 signal(n, f);
3479         }
3480 }
3481
3482 static int getn(char *as)
3483 {
3484         char *s;
3485         int n, m;
3486
3487         s = as;
3488         m = 1;
3489         if (*s == '-') {
3490                 m = -1;
3491                 s++;
3492         }
3493         for (n = 0; isdigit(*s); s++)
3494                 n = (n * 10) + (*s - '0');
3495         if (*s) {
3496                 prs(as);
3497                 err(": bad number");
3498         }
3499         return n * m;
3500 }
3501
3502 static int dobreak(struct op *t UNUSED_PARAM, char **args)
3503 {
3504         return brkcontin(args[1], 1);
3505 }
3506
3507 static int docontinue(struct op *t UNUSED_PARAM, char **args)
3508 {
3509         return brkcontin(args[1], 0);
3510 }
3511
3512 static int brkcontin(char *cp, int val)
3513 {
3514         struct brkcon *bc;
3515         int nl;
3516
3517         nl = cp == NULL ? 1 : getn(cp);
3518         if (nl <= 0)
3519                 nl = 999;
3520         do {
3521                 bc = brklist;
3522                 if (bc == NULL)
3523                         break;
3524                 brklist = bc->nextlev;
3525         } while (--nl);
3526         if (nl) {
3527                 err("bad break/continue level");
3528                 return 1;
3529         }
3530         isbreak = (val != 0);
3531         longjmp(bc->brkpt, 1);
3532         /* NOTREACHED */
3533 }
3534
3535 static int doexit(struct op *t UNUSED_PARAM, char **args)
3536 {
3537         char *cp;
3538
3539         execflg = 0;
3540         cp = args[1];
3541         if (cp != NULL)
3542                 setstatus(getn(cp));
3543
3544         DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3545
3546         leave();
3547         /* NOTREACHED */
3548         return 0;
3549 }
3550
3551 static int doexport(struct op *t UNUSED_PARAM, char **args)
3552 {
3553         rdexp(args + 1, export, EXPORT);
3554         return 0;
3555 }
3556
3557 static int doreadonly(struct op *t UNUSED_PARAM, char **args)
3558 {
3559         rdexp(args + 1, ronly, RONLY);
3560         return 0;
3561 }
3562
3563 static void rdexp(char **wp, void (*f) (struct var *), int key)
3564 {
3565         DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3566         DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3567
3568         if (*wp != NULL) {
3569                 for (; *wp != NULL; wp++) {
3570                         if (isassign(*wp)) {
3571                                 char *cp;
3572
3573                                 assign(*wp, COPYV);
3574                                 for (cp = *wp; *cp != '='; cp++)
3575                                         continue;
3576                                 *cp = '\0';
3577                         }
3578                         if (checkname(*wp))
3579                                 (*f) (lookup(*wp));
3580                         else
3581                                 badid(*wp);
3582                 }
3583         } else
3584                 putvlist(key, 1);
3585 }
3586
3587 static void badid(char *s)
3588 {
3589         prs(s);
3590         err(": bad identifier");
3591 }
3592
3593 static int doset(struct op *t UNUSED_PARAM, char **args)
3594 {
3595         struct var *vp;
3596         char *cp;
3597         int n;
3598
3599         cp = args[1];
3600         if (cp == NULL) {
3601                 for (vp = vlist; vp; vp = vp->next)
3602                         varput(vp->name, STDOUT_FILENO);
3603                 return 0;
3604         }
3605         if (*cp == '-') {
3606                 args++;
3607                 if (*++cp == 0)
3608                         FLAG['x'] = FLAG['v'] = 0;
3609                 else {
3610                         for (; *cp; cp++) {
3611                                 switch (*cp) {
3612                                 case 'e':
3613                                         if (!interactive)
3614                                                 FLAG['e']++;
3615                                         break;
3616
3617                                 default:
3618                                         if (*cp >= 'a' && *cp <= 'z')
3619                                                 FLAG[(int) *cp]++;
3620                                         break;
3621                                 }
3622                         }
3623                 }
3624                 setdash();
3625         }
3626         if (args[1]) {
3627                 args[0] = dolv[0];
3628                 for (n = 1; args[n]; n++)
3629                         setarea((char *) args[n], 0);
3630                 dolc = n - 1;
3631                 dolv = args;
3632                 setval(lookup("#"), putn(dolc));
3633                 setarea((char *) (dolv - 1), 0);
3634         }
3635         return 0;
3636 }
3637
3638 static void varput(char *s, int out)
3639 {
3640         if (isalnum(*s) || *s == '_') {
3641                 xwrite_str(out, s);
3642                 xwrite(out, "\n", 1);
3643         }
3644 }
3645
3646
3647 /*
3648  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3649  * This file contains code for the times builtin.
3650  */
3651 static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3652 {
3653         unsigned min, sec;
3654         if (sizeof(val) > sizeof(int))
3655                 sec = ((unsigned long)val) / clk_tck;
3656         else
3657                 sec = ((unsigned)val) / clk_tck;
3658         min = sec / 60;
3659 #if ENABLE_DESKTOP
3660         sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3661         /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3662         );
3663 #else
3664         sprintf(buf, "%um%us", min, (sec - min * 60));
3665 #endif
3666 }
3667
3668 static int dotimes(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3669 {
3670         struct tms buf;
3671         unsigned clk_tck = sysconf(_SC_CLK_TCK);
3672         /* How much do we need for "NmN.NNNs" ? */
3673         enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3674         char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3675         char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
3676
3677         times(&buf);
3678
3679         times_fmt(u, buf.tms_utime, clk_tck);
3680         times_fmt(s, buf.tms_stime, clk_tck);
3681         times_fmt(cu, buf.tms_cutime, clk_tck);
3682         times_fmt(cs, buf.tms_cstime, clk_tck);
3683
3684         printf("%s %s\n%s %s\n", u, s, cu, cs);
3685         return 0;
3686 }
3687
3688
3689 /* -------- eval.c -------- */
3690
3691 /*
3692  * ${}
3693  * `command`
3694  * blank interpretation
3695  * quoting
3696  * glob
3697  */
3698
3699 static char **eval(char **ap, int f)
3700 {
3701         struct wdblock *wb;
3702         char **wp;
3703         char **wf;
3704         jmp_buf ev;
3705
3706 #if __GNUC__
3707         /* Avoid longjmp clobbering */
3708         (void) &wp;
3709         (void) &ap;
3710 #endif
3711
3712         DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3713
3714         wp = NULL;
3715         wb = NULL;
3716         wf = NULL;
3717         errpt = ev;
3718         if (newenv(setjmp(errpt)) == 0) {
3719                 while (*ap && isassign(*ap))
3720                         expand(*ap++, &wb, f & ~DOGLOB);
3721                 if (FLAG['k']) {
3722                         for (wf = ap; *wf; wf++) {
3723                                 if (isassign(*wf))
3724                                         expand(*wf, &wb, f & ~DOGLOB);
3725                         }
3726                 }
3727                 for (wb = addword((char *) NULL, wb); *ap; ap++) {
3728                         if (!FLAG['k'] || !isassign(*ap))
3729                                 expand(*ap, &wb, f & ~DOKEY);
3730                 }
3731                 wb = addword((char *) 0, wb);
3732                 wp = getwords(wb);
3733                 quitenv();
3734         } else
3735                 gflg = 1;
3736
3737         return gflg ? (char **) NULL : wp;
3738 }
3739
3740
3741 /*
3742  * Make the exported environment from the exported
3743  * names in the dictionary. Keyword assignments
3744  * will already have been done.
3745  */
3746 static char **makenv(int all, struct wdblock *wb)
3747 {
3748         struct var *vp;
3749
3750         DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3751
3752         for (vp = vlist; vp; vp = vp->next)
3753                 if (all || vp->status & EXPORT)
3754                         wb = addword(vp->name, wb);
3755         wb = addword((char *) 0, wb);
3756         return getwords(wb);
3757 }
3758
3759 static int expand(const char *cp, struct wdblock **wbp, int f)
3760 {
3761         jmp_buf ev;
3762         char *xp;
3763
3764 #if __GNUC__
3765         /* Avoid longjmp clobbering */
3766         (void) &cp;
3767 #endif
3768
3769         DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3770
3771         gflg = 0;
3772
3773         if (cp == NULL)
3774                 return 0;
3775
3776         if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3777          && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3778         ) {
3779                 xp = strsave(cp, areanum);
3780                 if (f & DOTRIM)
3781                         unquote(xp);
3782                 *wbp = addword(xp, *wbp);
3783                 return 1;
3784         }
3785         errpt = ev;
3786         if (newenv(setjmp(errpt)) == 0) {
3787                 PUSHIO(aword, cp, strchar);
3788                 global_env.iobase = global_env.iop;
3789                 while ((xp = blank(f)) && gflg == 0) {
3790                         global_env.linep = xp;
3791                         xp = strsave(xp, areanum);
3792                         if ((f & DOGLOB) == 0) {
3793                                 if (f & DOTRIM)
3794                                         unquote(xp);
3795                                 *wbp = addword(xp, *wbp);
3796                         } else
3797                                 *wbp = glob(xp, *wbp);
3798                 }
3799                 quitenv();
3800         } else
3801                 gflg = 1;
3802         return gflg == 0;
3803 }
3804
3805 static char *evalstr(char *cp, int f)
3806 {
3807         struct wdblock *wb;
3808
3809         DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3810
3811         wb = NULL;
3812         if (expand(cp, &wb, f)) {
3813                 if (wb == NULL || wb->w_nword == 0
3814                  || (cp = wb->w_words[0]) == NULL
3815                 ) {
3816 // TODO: I suspect that
3817 // char *evalstr(char *cp, int f)  is actually
3818 // const char *evalstr(const char *cp, int f)!
3819                         cp = (char*)"";
3820                 }
3821                 DELETE(wb);
3822         } else
3823                 cp = NULL;
3824         return cp;
3825 }
3826
3827
3828 /*
3829  * Blank interpretation and quoting
3830  */
3831 static char *blank(int f)
3832 {
3833         int c, c1;
3834         char *sp;
3835         int scanequals, foundequals;
3836
3837         DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3838
3839         sp = global_env.linep;
3840         scanequals = f & DOKEY;
3841         foundequals = 0;
3842
3843  loop:
3844         c = subgetc('"', foundequals);
3845         switch (c) {
3846         case 0:
3847                 if (sp == global_env.linep)
3848                         return 0;
3849                 *global_env.linep++ = 0;
3850                 return sp;
3851
3852         default:
3853                 if (f & DOBLANK && any(c, ifs->value))
3854                         goto loop;
3855                 break;
3856
3857         case '"':
3858         case '\'':
3859                 scanequals = 0;
3860                 if (INSUB())
3861                         break;
3862                 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3863                         if (c == 0)
3864                                 break;
3865                         if (c == '\'' || !any(c, "$`\""))
3866                                 c |= QUOTE;
3867                         *global_env.linep++ = c;
3868                 }
3869                 c = 0;
3870         }
3871         unget(c);
3872         if (!isalpha(c) && c != '_')
3873                 scanequals = 0;
3874         for (;;) {
3875                 c = subgetc('"', foundequals);
3876                 if (c == 0
3877                  || f & (DOBLANK && any(c, ifs->value))
3878                  || (!INSUB() && any(c, "\"'"))
3879                 ) {
3880                         scanequals = 0;
3881                         unget(c);
3882                         if (any(c, "\"'"))
3883                                 goto loop;
3884                         break;
3885                 }
3886                 if (scanequals) {
3887                         if (c == '=') {
3888                                 foundequals = 1;
3889                                 scanequals = 0;
3890                         } else if (!isalnum(c) && c != '_')
3891                                 scanequals = 0;
3892                 }
3893                 *global_env.linep++ = c;
3894         }
3895         *global_env.linep++ = 0;
3896         return sp;
3897 }
3898
3899 /*
3900  * Get characters, substituting for ` and $
3901  */
3902 static int subgetc(char ec, int quoted)
3903 {
3904         char c;
3905
3906         DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3907
3908  again:
3909         c = my_getc(ec);
3910         if (!INSUB() && ec != '\'') {
3911                 if (c == '`') {
3912                         if (grave(quoted) == 0)
3913                                 return 0;
3914                         global_env.iop->task = XGRAVE;
3915                         goto again;
3916                 }
3917                 if (c == '$') {
3918                         c = dollar(quoted);
3919                         if (c == 0) {
3920                                 global_env.iop->task = XDOLL;
3921                                 goto again;
3922                         }
3923                 }
3924         }
3925         return c;
3926 }
3927
3928 /*
3929  * Prepare to generate the string returned by ${} substitution.
3930  */
3931 static int dollar(int quoted)
3932 {
3933         int otask;
3934         struct io *oiop;
3935         char *dolp;
3936         char *s, c, *cp = NULL;
3937         struct var *vp;
3938
3939         DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3940
3941         c = readc();
3942         s = global_env.linep;
3943         if (c != '{') {
3944                 *global_env.linep++ = c;
3945                 if (isalpha(c) || c == '_') {
3946                         while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3947                                 if (global_env.linep < elinep)
3948                                         *global_env.linep++ = c;
3949                         unget(c);
3950                 }
3951                 c = 0;
3952         } else {
3953                 oiop = global_env.iop;
3954                 otask = global_env.iop->task;
3955
3956                 global_env.iop->task = XOTHER;
3957                 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3958                         if (global_env.linep < elinep)
3959                                 *global_env.linep++ = c;
3960                 if (oiop == global_env.iop)
3961                         global_env.iop->task = otask;
3962                 if (c != '}') {
3963                         err("unclosed ${");
3964                         gflg = 1;
3965                         return c;
3966                 }
3967         }
3968         if (global_env.linep >= elinep) {
3969                 err("string in ${} too long");
3970                 gflg = 1;
3971                 global_env.linep -= 10;
3972         }
3973         *global_env.linep = 0;
3974         if (*s)
3975                 for (cp = s + 1; *cp; cp++)
3976                         if (any(*cp, "=-+?")) {
3977                                 c = *cp;
3978                                 *cp++ = 0;
3979                                 break;
3980                         }
3981         if (s[1] == 0 && (*s == '*' || *s == '@')) {
3982                 if (dolc > 1) {
3983                         /* currently this does not distinguish $* and $@ */
3984                         /* should check dollar */
3985                         global_env.linep = s;
3986                         PUSHIO(awordlist, dolv + 1, dolchar);
3987                         return 0;
3988                 } else {                                /* trap the nasty ${=} */
3989                         s[0] = '1';
3990                         s[1] = '\0';
3991                 }
3992         }
3993         vp = lookup(s);
3994         dolp = vp->value;
3995         if (dolp == null) {
3996                 switch (c) {
3997                 case '=':
3998                         if (isdigit(*s)) {
3999                                 err("can't use ${...=...} with $n");
4000                                 gflg = 1;
4001                                 break;
4002                         }
4003                         setval(vp, cp);
4004                         dolp = vp->value;
4005                         break;
4006
4007                 case '-':
4008                         dolp = strsave(cp, areanum);
4009                         break;
4010
4011                 case '?':
4012                         if (*cp == 0) {
4013                                 prs("missing value for ");
4014                                 err(s);
4015                         } else
4016                                 err(cp);
4017                         gflg = 1;
4018                         break;
4019                 }
4020         } else if (c == '+')
4021                 dolp = strsave(cp, areanum);
4022         if (FLAG['u'] && dolp == null) {
4023                 prs("unset variable: ");
4024                 err(s);
4025                 gflg = 1;
4026         }
4027         global_env.linep = s;
4028         PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4029         return 0;
4030 }
4031
4032 /*
4033  * Run the command in `...` and read its output.
4034  */
4035
4036 static int grave(int quoted)
4037 {
4038         /* moved to G: static char child_cmd[LINELIM]; */
4039
4040         const char *cp;
4041         int i;
4042         int j;
4043         int pf[2];
4044         const char *src;
4045         char *dest;
4046         int count;
4047         int ignore;
4048         int ignore_once;
4049         char *argument_list[4];
4050         struct wdblock *wb = NULL;
4051
4052 #if __GNUC__
4053         /* Avoid longjmp clobbering */
4054         (void) &cp;
4055 #endif
4056
4057         for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
4058                 if (*cp == 0) {
4059                         err("no closing `");
4060                         return 0;
4061                 }
4062         }
4063
4064         /* string copy with dollar expansion */
4065         src = global_env.iop->argp->aword;
4066         dest = child_cmd;
4067         count = 0;
4068         ignore = 0;
4069         ignore_once = 0;
4070         while ((*src != '`') && (count < LINELIM)) {
4071                 if (*src == '\'')
4072                         ignore = !ignore;
4073                 if (*src == '\\')
4074                         ignore_once = 1;
4075                 if (*src == '$' && !ignore && !ignore_once) {
4076                         struct var *vp;
4077                         /* moved to G to reduce stack usage
4078                         char var_name[LINELIM];
4079                         char alt_value[LINELIM];
4080                         */
4081 #define var_name (G.grave__var_name)
4082 #define alt_value (G.grave__alt_value)
4083                         int var_index = 0;
4084                         int alt_index = 0;
4085                         char operator = 0;
4086                         int braces = 0;
4087                         char *value;
4088
4089                         src++;
4090                         if (*src == '{') {
4091                                 braces = 1;
4092                                 src++;
4093                         }
4094
4095                         var_name[var_index++] = *src++;
4096                         while (isalnum(*src) || *src=='_')
4097                                 var_name[var_index++] = *src++;
4098                         var_name[var_index] = 0;
4099
4100                         if (braces) {
4101                                 switch (*src) {
4102                                 case '}':
4103                                         break;
4104                                 case '-':
4105                                 case '=':
4106                                 case '+':
4107                                 case '?':
4108                                         operator = * src;
4109                                         break;
4110                                 default:
4111                                         err("unclosed ${\n");
4112                                         return 0;
4113                                 }
4114                                 if (operator) {
4115                                         src++;
4116                                         while (*src && (*src != '}')) {
4117                                                 alt_value[alt_index++] = *src++;
4118                                         }
4119                                         alt_value[alt_index] = 0;
4120                                         if (*src != '}') {
4121                                                 err("unclosed ${\n");
4122                                                 return 0;
4123                                         }
4124                                 }
4125                                 src++;
4126                         }
4127
4128                         if (isalpha(*var_name)) {
4129                                 /* let subshell handle it instead */
4130
4131                                 char *namep = var_name;
4132
4133                                 *dest++ = '$';
4134                                 if (braces)
4135                                         *dest++ = '{';
4136                                 while (*namep)
4137                                         *dest++ = *namep++;
4138                                 if (operator) {
4139                                         char *altp = alt_value;
4140                                         *dest++ = operator;
4141                                         while (*altp)
4142                                                 *dest++ = *altp++;
4143                                 }
4144                                 if (braces)
4145                                         *dest++ = '}';
4146
4147                                 wb = addword(lookup(var_name)->name, wb);
4148                         } else {
4149                                 /* expand */
4150
4151                                 vp = lookup(var_name);
4152                                 if (vp->value != null)
4153                                         value = (operator == '+') ?
4154                                                 alt_value : vp->value;
4155                                 else if (operator == '?') {
4156                                         err(alt_value);
4157                                         return 0;
4158                                 } else if (alt_index && (operator != '+')) {
4159                                         value = alt_value;
4160                                         if (operator == '=')
4161                                                 setval(vp, value);
4162                                 } else
4163                                         continue;
4164
4165                                 while (*value && (count < LINELIM)) {
4166                                         *dest++ = *value++;
4167                                         count++;
4168                                 }
4169                         }
4170 #undef var_name
4171 #undef alt_value
4172                 } else {
4173                         *dest++ = *src++;
4174                         count++;
4175                         ignore_once = 0;
4176                 }
4177         }
4178         *dest = '\0';
4179
4180         if (openpipe(pf) < 0)
4181                 return 0;
4182
4183         while ((i = vfork()) == -1 && errno == EAGAIN)
4184                 continue;
4185
4186         DBGPRINTF3(("GRAVE: i is %p\n", io));
4187
4188         if (i < 0) {
4189                 closepipe(pf);
4190                 err((char *) bb_msg_memory_exhausted);
4191                 return 0;
4192         }
4193         if (i != 0) {
4194                 waitpid(i, NULL, 0); // safe_waitpid?
4195                 global_env.iop->argp->aword = ++cp;
4196                 close(pf[1]);
4197                 PUSHIO(afile, remap(pf[0]),
4198                         (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
4199                 return 1;
4200         }
4201         /* allow trapped signals */
4202         /* XXX - Maybe this signal stuff should go as well? */
4203         for (j = 0; j <= _NSIG; j++)
4204                 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4205                         signal(j, SIG_DFL);
4206
4207         /* Testcase where below checks are needed:
4208          * close stdout & run this script:
4209          *  files=`ls`
4210          *  echo "$files" >zz
4211          */
4212         xmove_fd(pf[1], 1);
4213         if (pf[0] != 1)
4214                 close(pf[0]);
4215
4216         argument_list[0] = (char *) DEFAULT_SHELL;
4217         argument_list[1] = (char *) "-c";
4218         argument_list[2] = child_cmd;
4219         argument_list[3] = NULL;
4220
4221         cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4222         prs(argument_list[0]);
4223         prs(": ");
4224         err(cp);
4225         _exit(EXIT_FAILURE);
4226 }
4227
4228
4229 static char *unquote(char *as)
4230 {
4231         char *s;
4232
4233         s = as;
4234         if (s != NULL)
4235                 while (*s)
4236                         *s++ &= ~QUOTE;
4237         return as;
4238 }
4239
4240 /* -------- glob.c -------- */
4241
4242 /*
4243  * glob
4244  */
4245
4246 #define scopy(x) strsave((x), areanum)
4247 #define BLKSIZ  512
4248 #define NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4249
4250 static struct wdblock *cl, *nl;
4251 static const char spcl[] ALIGN1= "[?*";
4252
4253 static struct wdblock *glob(char *cp, struct wdblock *wb)
4254 {
4255         int i;
4256         char *pp;
4257
4258         if (cp == 0)
4259                 return wb;
4260         i = 0;
4261         for (pp = cp; *pp; pp++)
4262                 if (any(*pp, spcl))
4263                         i++;
4264                 else if (!any(*pp & ~QUOTE, spcl))
4265                         *pp &= ~QUOTE;
4266         if (i != 0) {
4267                 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
4268                         nl = newword(cl->w_nword * 2);
4269                         for (i = 0; i < cl->w_nword; i++) {     /* for each argument */
4270                                 for (pp = cl->w_words[i]; *pp; pp++)
4271                                         if (any(*pp, spcl)) {
4272                                                 globname(cl->w_words[i], pp);
4273                                                 break;
4274                                         }
4275                                 if (*pp == '\0')
4276                                         nl = addword(scopy(cl->w_words[i]), nl);
4277                         }
4278                         for (i = 0; i < cl->w_nword; i++)
4279                                 DELETE(cl->w_words[i]);
4280                         DELETE(cl);
4281                 }
4282                 if (cl->w_nword) {
4283                         for (i = 0; i < cl->w_nword; i++)
4284                                 unquote(cl->w_words[i]);
4285                         qsort_string_vector(cl->w_words, cl->w_nword);
4286                         for (i = 0; i < cl->w_nword; i++)
4287                                 wb = addword(cl->w_words[i], wb);
4288                         DELETE(cl);
4289                         return wb;
4290                 }
4291         }
4292         wb = addword(unquote(cp), wb);
4293         return wb;
4294 }
4295
4296 static void globname(char *we, char *pp)
4297 {
4298         char *np, *cp;
4299         char *name, *gp, *dp;
4300         int k;
4301         DIR *dirp;
4302         struct dirent *de;
4303         char dname[NAME_MAX + 1];
4304         struct stat dbuf;
4305
4306         for (np = we; np != pp; pp--)
4307                 if (pp[-1] == '/')
4308                         break;
4309         dp = cp = get_space((int) (pp - np) + 3);
4310         while (np < pp)
4311                 *cp++ = *np++;
4312         *cp++ = '.';
4313         *cp = '\0';
4314         gp = cp = get_space(strlen(pp) + 1);
4315         while (*np && *np != '/')
4316                 *cp++ = *np++;
4317         *cp = '\0';
4318         dirp = opendir(dp);
4319         if (dirp == 0) {
4320                 DELETE(dp);
4321                 DELETE(gp);
4322                 return;
4323         }
4324         dname[NAME_MAX] = '\0';
4325         while ((de = readdir(dirp)) != NULL) {
4326                 /* XXX Hmmm... What this could be? (abial) */
4327                 /* if (ent[j].d_ino == 0) continue;
4328                  */
4329                 strncpy(dname, de->d_name, NAME_MAX);
4330                 if (dname[0] == '.')
4331                         if (*gp != '.')
4332                                 continue;
4333                 for (k = 0; k < NAME_MAX; k++)
4334                         if (any(dname[k], spcl))
4335                                 dname[k] |= QUOTE;
4336                 if (gmatch(dname, gp)) {
4337                         name = generate(we, pp, dname, np);
4338                         if (*np && !anys(np, spcl)) {
4339                                 if (stat(name, &dbuf)) {
4340                                         DELETE(name);
4341                                         continue;
4342                                 }
4343                         }
4344                         nl = addword(name, nl);
4345                 }
4346         }
4347         closedir(dirp);
4348         DELETE(dp);
4349         DELETE(gp);
4350 }
4351
4352 /*
4353  * generate a pathname as below.
4354  * start..end1 / middle end
4355  * the slashes come for free
4356  */
4357 static char *generate(char *start1, char *end1, char *middle, char *end)
4358 {
4359         char *p;
4360         char *op, *xp;
4361
4362         p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4363         xp = start1;
4364         while (xp != end1)
4365                 *op++ = *xp++;
4366         xp = middle;
4367         while (*xp != '\0')
4368                 *op++ = *xp++;
4369         strcpy(op, end);
4370         return p;
4371 }
4372
4373 static int anyspcl(struct wdblock *wb)
4374 {
4375         int i;
4376         char **wd;
4377
4378         wd = wb->w_words;
4379         for (i = 0; i < wb->w_nword; i++)
4380                 if (anys(spcl, *wd++))
4381                         return 1;
4382         return 0;
4383 }
4384
4385
4386 /* -------- word.c -------- */
4387
4388 static struct wdblock *newword(int nw)
4389 {
4390         struct wdblock *wb;
4391
4392         wb = get_space(sizeof(*wb) + nw * sizeof(char *));
4393         wb->w_bsize = nw;
4394         wb->w_nword = 0;
4395         return wb;
4396 }
4397
4398 static struct wdblock *addword(char *wd, struct wdblock *wb)
4399 {
4400         struct wdblock *wb2;
4401         int nw;
4402
4403         if (wb == NULL)
4404                 wb = newword(NSTART);
4405         nw = wb->w_nword;
4406         if (nw >= wb->w_bsize) {
4407                 wb2 = newword(nw * 2);
4408                 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4409                            nw * sizeof(char *));
4410                 wb2->w_nword = nw;
4411                 DELETE(wb);
4412                 wb = wb2;
4413         }
4414         wb->w_words[wb->w_nword++] = wd;
4415         return wb;
4416 }
4417
4418 static char **getwords(struct wdblock *wb)
4419 {
4420         char **wd;
4421         int nb;
4422
4423         if (wb == NULL)
4424                 return NULL;
4425         if (wb->w_nword == 0) {
4426                 DELETE(wb);
4427                 return NULL;
4428         }
4429         nb = sizeof(*wd) * wb->w_nword;
4430         wd = get_space(nb);
4431         memcpy(wd, wb->w_words, nb);
4432         DELETE(wb);                     /* perhaps should done by caller */
4433         return wd;
4434 }
4435
4436
4437 /* -------- io.c -------- */
4438
4439 /*
4440  * shell IO
4441  */
4442
4443 static int my_getc(int ec)
4444 {
4445         int c;
4446
4447         if (global_env.linep > elinep) {
4448                 while ((c = readc()) != '\n' && c)
4449                         continue;
4450                 err("input line too long");
4451                 gflg = 1;
4452                 return c;
4453         }
4454         c = readc();
4455         if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
4456                 if (c == '\\') {
4457                         c = readc();
4458                         if (c == '\n' && ec != '\"')
4459                                 return my_getc(ec);
4460                         c |= QUOTE;
4461                 }
4462         }
4463         return c;
4464 }
4465
4466 static void unget(int c)
4467 {
4468         if (global_env.iop >= global_env.iobase)
4469                 global_env.iop->peekc = c;
4470 }
4471
4472 static int eofc(void)
4473 {
4474         return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
4475 }
4476
4477 static int readc(void)
4478 {
4479         int c;
4480
4481         RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
4482
4483         for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4484                 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4485                 c = global_env.iop->peekc;
4486                 if (c != '\0') {
4487                         global_env.iop->peekc = 0;
4488                         return c;
4489                 }
4490                 if (global_env.iop->prev != 0) {
4491                         c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
4492                         if (c != '\0') {
4493                                 if (c == -1) {
4494                                         global_env.iop++;
4495                                         continue;
4496                                 }
4497                                 if (global_env.iop == iostack)
4498                                         ioecho(c);
4499                                 global_env.iop->prev = c;
4500                                 return c;
4501                         }
4502                         if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4503                                 global_env.iop->prev = 0;
4504                                 if (global_env.iop == iostack)
4505                                         ioecho('\n');
4506                                 return '\n';
4507                         }
4508                 }
4509                 if (global_env.iop->task == XIO) {
4510                         if (multiline) {
4511                                 global_env.iop->prev = 0;
4512                                 return 0;
4513                         }
4514                         if (interactive && global_env.iop == iostack + 1) {
4515 #if ENABLE_FEATURE_EDITING
4516                                 current_prompt = prompt->value;
4517 #else
4518                                 prs(prompt->value);
4519 #endif
4520                         }
4521                 }
4522         }                                                       /* FOR */
4523
4524         if (global_env.iop >= iostack) {
4525                 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
4526                 return 0;
4527         }
4528
4529         DBGPRINTF(("READC: leave()...\n"));
4530         leave();
4531         /* NOTREACHED */
4532         return 0;
4533 }
4534
4535 static void ioecho(char c)
4536 {
4537         if (FLAG['v'])
4538                 write(STDERR_FILENO, &c, sizeof c);
4539 }
4540
4541 static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4542 {
4543         DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4544                            argp->afid, global_env.iop));
4545
4546         /* Set env ptr for io source to next array spot and check for array overflow */
4547         if (++global_env.iop >= &iostack[NPUSH]) {
4548                 global_env.iop--;
4549                 err("Shell input nested too deeply");
4550                 gflg = 1;
4551                 return;
4552         }
4553
4554         /* We did not overflow the NPUSH array spots so setup data structs */
4555
4556         global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn;       /* Store data source func ptr */
4557
4558         if (argp->afid != AFID_NOBUF)
4559                 global_env.iop->argp = argp;
4560         else {
4561
4562                 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4563                 *global_env.iop->argp = *argp;  /* copy data from temp area into stack spot */
4564
4565                 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4566
4567                 if (global_env.iop == &iostack[0])
4568                         global_env.iop->argp->afbuf = &mainbuf;
4569                 else
4570                         global_env.iop->argp->afbuf = &sharedbuf;
4571
4572                 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4573                 /* This line appears to be active when running scripts from command line */
4574                 if ((isatty(global_env.iop->argp->afile) == 0)
4575                         && (global_env.iop == &iostack[0]
4576                                 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4577                         if (++bufid == AFID_NOBUF)      /* counter rollover check, AFID_NOBUF = 11111111  */
4578                                 bufid = AFID_ID;        /* AFID_ID = 0 */
4579
4580                         global_env.iop->argp->afid = bufid;     /* assign buffer id */
4581                 }
4582
4583                 DBGPRINTF(("PUSHIO: iostack %p,  global_env.iop %p, afbuf %p\n",
4584                                    iostack, global_env.iop, global_env.iop->argp->afbuf));
4585                 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4586                                    &mainbuf, &sharedbuf, bufid, global_env.iop));
4587
4588         }
4589
4590         global_env.iop->prev = ~'\n';
4591         global_env.iop->peekc = 0;
4592         global_env.iop->xchar = 0;
4593         global_env.iop->nlcount = 0;
4594
4595         if (fn == filechar || fn == linechar)
4596                 global_env.iop->task = XIO;
4597         else if (fn == (int (*)(struct ioarg *)) gravechar
4598               || fn == (int (*)(struct ioarg *)) qgravechar)
4599                 global_env.iop->task = XGRAVE;
4600         else
4601                 global_env.iop->task = XOTHER;
4602 }
4603
4604 static struct io *setbase(struct io *ip)
4605 {
4606         struct io *xp;
4607
4608         xp = global_env.iobase;
4609         global_env.iobase = ip;
4610         return xp;
4611 }
4612
4613 /*
4614  * Input generating functions
4615  */
4616
4617 /*
4618  * Produce the characters of a string, then a newline, then NUL.
4619  */
4620 static int nlchar(struct ioarg *ap)
4621 {
4622         char c;
4623
4624         if (ap->aword == NULL)
4625                 return '\0';
4626         c = *ap->aword++;
4627         if (c == '\0') {
4628                 ap->aword = NULL;
4629                 return '\n';
4630         }
4631         return c;
4632 }
4633
4634 /*
4635  * Given a list of words, produce the characters
4636  * in them, with a space after each word.
4637  */
4638 static int wdchar(struct ioarg *ap)
4639 {
4640         char c;
4641         char **wl;
4642
4643         wl = ap->awordlist;
4644         if (wl == NULL)
4645                 return 0;
4646         if (*wl != NULL) {
4647                 c = *(*wl)++;
4648                 if (c != 0)
4649                         return c & 0177;
4650                 ap->awordlist++;
4651                 return ' ';
4652         }
4653         ap->awordlist = NULL;
4654         return '\n';
4655 }
4656
4657 /*
4658  * Return the characters of a list of words,
4659  * producing a space between them.
4660  */
4661 static int dolchar(struct ioarg *ap)
4662 {
4663         char *wp;
4664
4665         wp = *ap->awordlist++;
4666         if (wp != NULL) {
4667                 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4668                 return -1;
4669         }
4670         return 0;
4671 }
4672
4673 static int xxchar(struct ioarg *ap)
4674 {
4675         int c;
4676
4677         if (ap->aword == NULL)
4678                 return 0;
4679         c = *ap->aword++;
4680         if (c == '\0') {
4681                 ap->aword = NULL;
4682                 return ' ';
4683         }
4684         return c;
4685 }
4686
4687 /*
4688  * Produce the characters from a single word (string).
4689  */
4690 static int strchar(struct ioarg *ap)
4691 {
4692         if (ap->aword == NULL)
4693                 return 0;
4694         return *ap->aword++;
4695 }
4696
4697 /*
4698  * Produce quoted characters from a single word (string).
4699  */
4700 static int qstrchar(struct ioarg *ap)
4701 {
4702         int c;
4703
4704         if (ap->aword == NULL)
4705                 return 0;
4706         c = *ap->aword++;
4707         if (c)
4708                 c |= QUOTE;
4709         return c;
4710 }
4711
4712 /*
4713  * Return the characters from a file.
4714  */
4715 static int filechar(struct ioarg *ap)
4716 {
4717         int i;
4718         char c;
4719         struct iobuf *bp = ap->afbuf;
4720
4721         if (ap->afid != AFID_NOBUF) {
4722                 i = (ap->afid != bp->id);
4723                 if (i || bp->bufp == bp->ebufp) {
4724                         if (i)
4725                                 lseek(ap->afile, ap->afpos, SEEK_SET);
4726
4727                         i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4728                         if (i <= 0) {
4729                                 closef(ap->afile);
4730                                 return 0;
4731                         }
4732
4733                         bp->id = ap->afid;
4734                         bp->bufp = bp->buf;
4735                         bp->ebufp = bp->bufp + i;
4736                 }
4737
4738                 ap->afpos++;
4739                 return *bp->bufp++ & 0177;
4740         }
4741 #if ENABLE_FEATURE_EDITING
4742         if (interactive && isatty(ap->afile)) {
4743                 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
4744                 static int position = 0, size = 0;
4745
4746                 while (size == 0 || position >= size) {
4747                         size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4748                         if (size < 0) /* Error/EOF */
4749                                 exit(EXIT_SUCCESS);
4750                         position = 0;
4751                         /* if Ctrl-C, size == 0 and loop will repeat */
4752                 }
4753                 c = filechar_cmdbuf[position];
4754                 position++;
4755                 return c;
4756         }
4757 #endif
4758         i = nonblock_safe_read(ap->afile, &c, sizeof(c));
4759         return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4760 }
4761
4762 /*
4763  * Return the characters from a here temp file.
4764  */
4765 static int herechar(struct ioarg *ap)
4766 {
4767         char c;
4768
4769         if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4770                 close(ap->afile);
4771                 c = '\0';
4772         }
4773         return c;
4774 }
4775
4776 /*
4777  * Return the characters produced by a process (`...`).
4778  * Quote them if required, and remove any trailing newline characters.
4779  */
4780 static int gravechar(struct ioarg *ap, struct io *iop)
4781 {
4782         int c;
4783
4784         c = qgravechar(ap, iop) & ~QUOTE;
4785         if (c == '\n')
4786                 c = ' ';
4787         return c;
4788 }
4789
4790 static int qgravechar(struct ioarg *ap, struct io *iop)
4791 {
4792         int c;
4793
4794         DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4795
4796         if (iop->xchar) {
4797                 if (iop->nlcount) {
4798                         iop->nlcount--;
4799                         return '\n' | QUOTE;
4800                 }
4801                 c = iop->xchar;
4802                 iop->xchar = 0;
4803         } else if ((c = filechar(ap)) == '\n') {
4804                 iop->nlcount = 1;
4805                 while ((c = filechar(ap)) == '\n')
4806                         iop->nlcount++;
4807                 iop->xchar = c;
4808                 if (c == 0)
4809                         return c;
4810                 iop->nlcount--;
4811                 c = '\n';
4812         }
4813         return c != 0 ? c | QUOTE : 0;
4814 }
4815
4816 /*
4817  * Return a single command (usually the first line) from a file.
4818  */
4819 static int linechar(struct ioarg *ap)
4820 {
4821         int c;
4822
4823         c = filechar(ap);
4824         if (c == '\n') {
4825                 if (!multiline) {
4826                         closef(ap->afile);
4827                         ap->afile = -1;         /* illegal value */
4828                 }
4829         }
4830         return c;
4831 }
4832
4833 /*
4834  * Remap fd into shell's fd space
4835  */
4836 static int remap(int fd)
4837 {
4838         int i;
4839         int map[NOFILE];
4840         int newfd;
4841
4842         DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
4843
4844         if (fd < global_env.iofd) {
4845                 for (i = 0; i < NOFILE; i++)
4846                         map[i] = 0;
4847
4848                 do {
4849                         map[fd] = 1;
4850                         newfd = dup(fd);
4851                         fd = newfd;
4852                 } while (fd >= 0 && fd < global_env.iofd);
4853
4854                 for (i = 0; i < NOFILE; i++)
4855                         if (map[i])
4856                                 close(i);
4857
4858                 if (fd < 0)
4859                         err("too many files open in shell");
4860         }
4861
4862         return fd;
4863 }
4864
4865 static int openpipe(int *pv)
4866 {
4867         int i;
4868
4869         i = pipe(pv);
4870         if (i < 0)
4871                 err("can't create pipe - try again");
4872         return i;
4873 }
4874
4875 static void closepipe(int *pv)
4876 {
4877         if (pv != NULL) {
4878                 close(pv[0]);
4879                 close(pv[1]);
4880         }
4881 }
4882
4883
4884 /* -------- here.c -------- */
4885
4886 /*
4887  * here documents
4888  */
4889
4890 static void markhere(char *s, struct ioword *iop)
4891 {
4892         struct here *h, *lh;
4893
4894         DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
4895
4896         h = get_space(sizeof(struct here));
4897         if (h == NULL)
4898                 return;
4899
4900         h->h_tag = evalstr(s, DOSUB);
4901         if (h->h_tag == 0)
4902                 return;
4903
4904         h->h_iop = iop;
4905         iop->io_name = 0;
4906         h->h_next = NULL;
4907         if (inhere == 0)
4908                 inhere = h;
4909         else {
4910                 for (lh = inhere; lh != NULL; lh = lh->h_next) {
4911                         if (lh->h_next == 0) {
4912                                 lh->h_next = h;
4913                                 break;
4914                         }
4915                 }
4916         }
4917         iop->io_flag |= IOHERE | IOXHERE;
4918         for (s = h->h_tag; *s; s++) {
4919                 if (*s & QUOTE) {
4920                         iop->io_flag &= ~IOXHERE;
4921                         *s &= ~QUOTE;
4922                 }
4923         }
4924         h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
4925 }
4926
4927 static void gethere(void)
4928 {
4929         struct here *h, *hp;
4930
4931         DBGPRINTF7(("GETHERE: enter...\n"));
4932
4933         /* Scan here files first leaving inhere list in place */
4934         for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
4935                 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
4936
4937         /* Make inhere list active - keep list intact for scraphere */
4938         if (hp != NULL) {
4939                 hp->h_next = acthere;
4940                 acthere = inhere;
4941                 inhere = NULL;
4942         }
4943 }
4944
4945 static void readhere(char **name, char *s, int ec)
4946 {
4947         int tf;
4948         char tname[30] = ".msh_XXXXXX";
4949         int c;
4950         jmp_buf ev;
4951         char myline[LINELIM + 1];
4952         char *thenext;
4953
4954         DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
4955
4956         tf = mkstemp(tname);
4957         if (tf < 0)
4958                 return;
4959
4960         *name = strsave(tname, areanum);
4961         errpt = ev;
4962         if (newenv(setjmp(errpt)) != 0)
4963                 unlink(tname);
4964         else {
4965                 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4966                 global_env.iobase = global_env.iop;
4967                 for (;;) {
4968                         if (interactive && global_env.iop <= iostack) {
4969 #if ENABLE_FEATURE_EDITING
4970                                 current_prompt = cprompt->value;
4971 #else
4972                                 prs(cprompt->value);
4973 #endif
4974                         }
4975                         thenext = myline;
4976                         while ((c = my_getc(ec)) != '\n' && c) {
4977                                 if (ec == '\'')
4978                                         c &= ~QUOTE;
4979                                 if (thenext >= &myline[LINELIM]) {
4980                                         c = 0;
4981                                         break;
4982                                 }
4983                                 *thenext++ = c;
4984                         }
4985                         *thenext = 0;
4986                         if (strcmp(s, myline) == 0 || c == 0)
4987                                 break;
4988                         *thenext++ = '\n';
4989                         write(tf, myline, (int) (thenext - myline));
4990                 }
4991                 if (c == 0) {
4992                         prs("here document `");
4993                         prs(s);
4994                         err("' unclosed");
4995                 }
4996                 quitenv();
4997         }
4998         close(tf);
4999 }
5000
5001 /*
5002  * open here temp file.
5003  * if unquoted here, expand here temp file into second temp file.
5004  */
5005 static int herein(char *hname, int xdoll)
5006 {
5007         int hf;
5008         int tf;
5009
5010 #if __GNUC__
5011         /* Avoid longjmp clobbering */
5012         (void) &tf;
5013 #endif
5014         if (hname == NULL)
5015                 return -1;
5016
5017         DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5018
5019         hf = open(hname, O_RDONLY);
5020         if (hf < 0)
5021                 return -1;
5022
5023         if (xdoll) {
5024                 char c;
5025                 char tname[30] = ".msh_XXXXXX";
5026                 jmp_buf ev;
5027
5028                 tf = mkstemp(tname);
5029                 if (tf < 0)
5030                         return -1;
5031                 errpt = ev;
5032                 if (newenv(setjmp(errpt)) == 0) {
5033                         PUSHIO(afile, hf, herechar);
5034                         setbase(global_env.iop);
5035                         while ((c = subgetc(0, 0)) != 0) {
5036                                 c &= ~QUOTE;
5037                                 write(tf, &c, sizeof c);
5038                         }
5039                         quitenv();
5040                 } else
5041                         unlink(tname);
5042                 close(tf);
5043                 tf = open(tname, O_RDONLY);
5044                 unlink(tname);
5045                 return tf;
5046         }
5047         return hf;
5048 }
5049
5050 static void scraphere(void)
5051 {
5052         struct here *h;
5053
5054         DBGPRINTF7(("SCRAPHERE: enter...\n"));
5055
5056         for (h = inhere; h != NULL; h = h->h_next) {
5057                 if (h->h_iop && h->h_iop->io_name)
5058                         unlink(h->h_iop->io_name);
5059         }
5060         inhere = NULL;
5061 }
5062
5063 /* unlink here temp files before a freearea(area) */
5064 static void freehere(int area)
5065 {
5066         struct here *h, *hl;
5067
5068         DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5069
5070         hl = NULL;
5071         for (h = acthere; h != NULL; h = h->h_next) {
5072                 if (getarea((char *) h) >= area) {
5073                         if (h->h_iop->io_name != NULL)
5074                                 unlink(h->h_iop->io_name);
5075                         if (hl == NULL)
5076                                 acthere = h->h_next;
5077                         else
5078                                 hl->h_next = h->h_next;
5079                 } else {
5080                         hl = h;
5081                 }
5082         }
5083 }
5084
5085
5086 /* -------- sh.c -------- */
5087 /*
5088  * shell
5089  */
5090
5091 int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
5092 int msh_main(int argc, char **argv)
5093 {
5094         int f;
5095         char *s;
5096         int cflag;
5097         char *name, **ap;
5098         int (*iof) (struct ioarg *);
5099
5100         INIT_G();
5101
5102         sharedbuf.id = AFID_NOBUF;
5103         mainbuf.id = AFID_NOBUF;
5104         elinep = line + sizeof(line) - 5;
5105
5106 #if ENABLE_FEATURE_EDITING
5107         line_input_state = new_line_input_t(FOR_SHELL);
5108 #endif
5109
5110         DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5111
5112         initarea();
5113         ap = environ;
5114         if (ap != NULL) {
5115                 while (*ap)
5116                         assign(*ap++, !COPYV);
5117                 for (ap = environ; *ap;)
5118                         export(lookup(*ap++));
5119         }
5120         closeall();
5121         areanum = 1;
5122
5123         shell = lookup("SHELL");
5124         if (shell->value == null)
5125                 setval(shell, (char *)DEFAULT_SHELL);
5126         export(shell);
5127
5128         homedir = lookup("HOME");
5129         if (homedir->value == null)
5130                 setval(homedir, "/");
5131         export(homedir);
5132
5133         setval(lookup("$"), putn(getpid()));
5134
5135         path = lookup("PATH");
5136         if (path->value == null) {
5137                 /* Can be merged with same string elsewhere in bbox */
5138                 if (geteuid() == 0)
5139                         setval(path, bb_default_root_path);
5140                 else
5141                         setval(path, bb_default_path);
5142         }
5143         export(path);
5144
5145         ifs = lookup("IFS");
5146         if (ifs->value == null)
5147                 setval(ifs, " \t\n");
5148
5149 #ifdef MSHDEBUG
5150         mshdbg_var = lookup("MSHDEBUG");
5151         if (mshdbg_var->value == null)
5152                 setval(mshdbg_var, "0");
5153 #endif
5154
5155         prompt = lookup("PS1");
5156 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5157         if (prompt->value == null)
5158 #endif
5159                 setval(prompt, DEFAULT_USER_PROMPT);
5160         if (geteuid() == 0) {
5161                 setval(prompt, DEFAULT_ROOT_PROMPT);
5162                 prompt->status &= ~EXPORT;
5163         }
5164         cprompt = lookup("PS2");
5165 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5166         if (cprompt->value == null)
5167 #endif
5168                 setval(cprompt, "> ");
5169
5170         iof = filechar;
5171         cflag = 0;
5172         name = *argv++;
5173         if (--argc >= 1) {
5174                 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5175                         for (s = argv[0] + 1; *s; s++)
5176                                 switch (*s) {
5177                                 case 'c':
5178                                         prompt->status &= ~EXPORT;
5179                                         cprompt->status &= ~EXPORT;
5180                                         setval(prompt, "");
5181                                         setval(cprompt, "");
5182                                         cflag = 1;
5183                                         if (--argc > 0)
5184                                                 PUSHIO(aword, *++argv, iof = nlchar);
5185                                         break;
5186
5187                                 case 'q':
5188                                         qflag = SIG_DFL;
5189                                         break;
5190
5191                                 case 's':
5192                                         /* standard input */
5193                                         break;
5194
5195                                 case 't':
5196                                         prompt->status &= ~EXPORT;
5197                                         setval(prompt, "");
5198                                         iof = linechar;
5199                                         break;
5200
5201                                 case 'i':
5202                                         interactive = 1;
5203                                 default:
5204                                         if (*s >= 'a' && *s <= 'z')
5205                                                 FLAG[(int) *s]++;
5206                                 }
5207                 } else {
5208                         argv--;
5209                         argc++;
5210                 }
5211
5212                 if (iof == filechar && --argc > 0) {
5213                         setval(prompt, "");
5214                         setval(cprompt, "");
5215                         prompt->status &= ~EXPORT;
5216                         cprompt->status &= ~EXPORT;
5217
5218 /* Shell is non-interactive, activate printf-based debug */
5219 #ifdef MSHDEBUG
5220                         mshdbg = mshdbg_var->value[0] - '0';
5221                         if (mshdbg < 0)
5222                                 mshdbg = 0;
5223 #endif
5224                         DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5225
5226                         name = *++argv;
5227                         if (newfile(name))
5228                                 exit(EXIT_FAILURE);  /* Exit on error */
5229                 }
5230         }
5231
5232         setdash();
5233
5234         /* This won't be true if PUSHIO has been called, say from newfile() above */
5235         if (global_env.iop < iostack) {
5236                 PUSHIO(afile, 0, iof);
5237                 if (isatty(0) && isatty(1) && !cflag) {
5238                         interactive = 1;
5239 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
5240 #ifdef MSHDEBUG
5241                         printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
5242 #else
5243                         printf("\n\n%s built-in shell (msh)\n", bb_banner);
5244 #endif
5245                         printf("Enter 'help' for a list of built-in commands.\n\n");
5246 #endif
5247                 }
5248         }
5249
5250         signal(SIGQUIT, qflag);
5251         if (name && name[0] == '-') {
5252                 interactive = 1;
5253                 f = open(".profile", O_RDONLY);
5254                 if (f >= 0)
5255                         next(remap(f));
5256                 f = open("/etc/profile", O_RDONLY);
5257                 if (f >= 0)
5258                         next(remap(f));
5259         }
5260         if (interactive)
5261                 signal(SIGTERM, sig);
5262
5263         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5264                 signal(SIGINT, onintr);
5265
5266 /* Handle "msh SCRIPT VAR=val params..." */
5267 /* Disabled: bash does not do it! */
5268 #if 0
5269         argv++;
5270         /* skip leading args of the form VAR=val */
5271         while (*argv && assign(*argv, !COPYV)) {
5272                 argc--;
5273                 argv++;
5274         }
5275         argv--;
5276 #endif
5277         dolv = argv;
5278         dolc = argc;
5279         dolv[0] = name;
5280
5281         setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5282
5283         DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
5284
5285         for (;;) {
5286                 if (interactive && global_env.iop <= iostack) {
5287 #if ENABLE_FEATURE_EDITING
5288                         current_prompt = prompt->value;
5289 #else
5290                         prs(prompt->value);
5291 #endif
5292                 }
5293                 onecommand();
5294                 /* Ensure that getenv("PATH") stays current */
5295                 setenv("PATH", path->value, 1);
5296         }
5297
5298         DBGPRINTF(("MSH_MAIN: returning.\n"));
5299 }
5300
5301
5302 /*
5303  * Copyright (c) 1987,1997, Prentice Hall
5304  * All rights reserved.
5305  *
5306  * Redistribution and use of the MINIX operating system in source and
5307  * binary forms, with or without modification, are permitted provided
5308  * that the following conditions are met:
5309  *
5310  * Redistributions of source code must retain the above copyright
5311  * notice, this list of conditions and the following disclaimer.
5312  *
5313  * Redistributions in binary form must reproduce the above
5314  * copyright notice, this list of conditions and the following
5315  * disclaimer in the documentation and/or other materials provided
5316  * with the distribution.
5317  *
5318  * Neither the name of Prentice Hall nor the names of the software
5319  * authors or contributors may be used to endorse or promote
5320  * products derived from this software without specific prior
5321  * written permission.
5322  *
5323  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5324  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5325  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5326  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5327  * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5328  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5329  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5330  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5331  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5332  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5333  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5334  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5335  *
5336  */