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