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