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