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