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