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