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