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