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