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