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