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