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