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