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