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