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