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