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