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