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