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