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