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