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