492d3cf43f3c62b06c6a667b5d8372b095270e3c
[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 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 : 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 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 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 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 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 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 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, cannot 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 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 NULL;
3032 }
3033
3034 static struct op *findcase(struct op *t, char *w)
3035 {
3036         struct op **tp;
3037
3038         tp = find1case(t, w);
3039         return tp != NULL ? *tp : NULL;
3040 }
3041
3042 /*
3043  * Enter a new loop level (marked for break/continue).
3044  */
3045 static void brkset(struct brkcon *bc)
3046 {
3047         bc->nextlev = brklist;
3048         brklist = bc;
3049 }
3050
3051 /*
3052  * Wait for the last process created.
3053  * Print a message for each process found
3054  * that was killed by a signal.
3055  * Ignore interrupt signals while waiting
3056  * unless `canintr' is true.
3057  */
3058 static int waitfor(int lastpid, int canintr)
3059 {
3060         int pid, rv;
3061         int s;
3062         int oheedint = heedint;
3063
3064         heedint = 0;
3065         rv = 0;
3066         do {
3067                 pid = wait(&s);
3068                 if (pid == -1) {
3069                         if (errno != EINTR || canintr)
3070                                 break;
3071                 } else {
3072                         if ((rv = WAITSIG(s)) != 0) {
3073                                 if (rv < NSIGNAL) {
3074                                         if (signame[rv] != NULL) {
3075                                                 if (pid != lastpid) {
3076                                                         prn(pid);
3077                                                         prs(": ");
3078                                                 }
3079                                                 prs(signame[rv]);
3080                                         }
3081                                 } else {
3082                                         if (pid != lastpid) {
3083                                                 prn(pid);
3084                                                 prs(": ");
3085                                         }
3086                                         prs("Signal ");
3087                                         prn(rv);
3088                                         prs(" ");
3089                                 }
3090                                 if (WAITCORE(s))
3091                                         prs(" - core dumped");
3092                                 if (rv >= NSIGNAL || signame[rv])
3093                                         prs("\n");
3094                                 rv = -1;
3095                         } else
3096                                 rv = WAITVAL(s);
3097                 }
3098         } while (pid != lastpid);
3099         heedint = oheedint;
3100         if (intr) {
3101                 if (interactive) {
3102                         if (canintr)
3103                                 intr = 0;
3104                 } else {
3105                         if (exstat == 0)
3106                                 exstat = rv;
3107                         onintr(0);
3108                 }
3109         }
3110         return rv;
3111 }
3112
3113 static int setstatus(int s)
3114 {
3115         exstat = s;
3116         setval(lookup("?"), putn(s));
3117         return s;
3118 }
3119
3120 /*
3121  * PATH-searching interface to execve.
3122  * If getenv("PATH") were kept up-to-date,
3123  * execvp might be used.
3124  */
3125 static char *rexecve(char *c, char **v, char **envp)
3126 {
3127         int i;
3128         char *sp, *tp;
3129         int eacces = 0, asis = 0;
3130         char *name = c;
3131
3132         if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
3133                 optind = 1;
3134                 if (find_applet_by_name(name)) {
3135                         /* We have to exec here since we vforked.  Running
3136                          * run_applet_by_name() won't work and bad things
3137                          * will happen. */
3138                         execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
3139                 }
3140         }
3141
3142         DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3143
3144         sp = any('/', c) ? "" : path->value;
3145         asis = *sp == '\0';
3146         while (asis || *sp != '\0') {
3147                 asis = 0;
3148                 tp = e.linep;
3149                 for (; *sp != '\0'; tp++)
3150                         if ((*tp = *sp++) == ':') {
3151                                 asis = *sp == '\0';
3152                                 break;
3153                         }
3154                 if (tp != e.linep)
3155                         *tp++ = '/';
3156                 for (i = 0; (*tp++ = c[i++]) != '\0';);
3157
3158                 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3159
3160                 execve(e.linep, v, envp);
3161
3162                 switch (errno) {
3163                 case ENOEXEC:
3164                         *v = e.linep;
3165                         tp = *--v;
3166                         *v = e.linep;
3167                         execve(DEFAULT_SHELL, v, envp);
3168                         *v = tp;
3169                         return "no Shell";
3170
3171                 case ENOMEM:
3172                         return (char *) bb_msg_memory_exhausted;
3173
3174                 case E2BIG:
3175                         return "argument list too long";
3176
3177                 case EACCES:
3178                         eacces++;
3179                         break;
3180                 }
3181         }
3182         return errno == ENOENT ? "not found" : "cannot execute";
3183 }
3184
3185 /*
3186  * Run the command produced by generator `f'
3187  * applied to stream `arg'.
3188  */
3189 static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3190 {
3191         struct op *otree;
3192         struct wdblock *swdlist;
3193         struct wdblock *siolist;
3194         jmp_buf ev, rt;
3195         xint *ofail;
3196         int rv;
3197
3198 #if __GNUC__
3199         /* Avoid longjmp clobbering */
3200         (void) &rv;
3201 #endif
3202
3203         DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3204                            areanum, outtree, failpt));
3205
3206         areanum++;
3207         swdlist = wdlist;
3208         siolist = iolist;
3209         otree = outtree;
3210         ofail = failpt;
3211         rv = -1;
3212
3213         if (newenv(setjmp(errpt = ev)) == 0) {
3214                 wdlist = 0;
3215                 iolist = 0;
3216                 pushio(argp, f);
3217                 e.iobase = e.iop;
3218                 yynerrs = 0;
3219                 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3220                         rv = execute(outtree, NOPIPE, NOPIPE, 0);
3221                 quitenv();
3222         } else {
3223                 DBGPRINTF(("RUN: error from newenv()!\n"));
3224         }
3225
3226         wdlist = swdlist;
3227         iolist = siolist;
3228         failpt = ofail;
3229         outtree = otree;
3230         freearea(areanum--);
3231
3232         return rv;
3233 }
3234
3235 /* -------- do.c -------- */
3236
3237 /*
3238  * built-in commands: doX
3239  */
3240
3241 static int dohelp(struct op *t)
3242 {
3243         int col;
3244         const struct builtincmd *x;
3245
3246         printf("\nBuilt-in commands:\n");
3247         printf("-------------------\n");
3248
3249         for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
3250                 if (!x->name)
3251                         continue;
3252                 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3253                 if (col > 60) {
3254                         puts("");
3255                         col = 0;
3256                 }
3257         }
3258 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3259         {
3260                 int i;
3261                 const struct BB_applet *applet;
3262                 extern const struct BB_applet applets[];
3263                 extern const size_t NUM_APPLETS;
3264
3265                 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
3266                         if (!applet->name)
3267                                 continue;
3268
3269                         col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
3270                         if (col > 60) {
3271                                 puts("");
3272                                 col = 0;
3273                         }
3274                 }
3275         }
3276 #endif
3277         printf("\n\n");
3278         return EXIT_SUCCESS;
3279 }
3280
3281
3282
3283 static int dolabel(struct op *t)
3284 {
3285         return 0;
3286 }
3287
3288 static int dochdir(struct op *t)
3289 {
3290         char *cp, *er;
3291
3292         if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3293                 er = ": no home directory";
3294         else if (chdir(cp) < 0)
3295                 er = ": bad directory";
3296         else
3297                 return 0;
3298         prs(cp != NULL ? cp : "cd");
3299         err(er);
3300         return 1;
3301 }
3302
3303 static int doshift(struct op *t)
3304 {
3305         int n;
3306
3307         n = t->words[1] ? getn(t->words[1]) : 1;
3308         if (dolc < n) {
3309                 err("nothing to shift");
3310                 return 1;
3311         }
3312         dolv[n] = dolv[0];
3313         dolv += n;
3314         dolc -= n;
3315         setval(lookup("#"), putn(dolc));
3316         return 0;
3317 }
3318
3319 /*
3320  * execute login and newgrp directly
3321  */
3322 static int dologin(struct op *t)
3323 {
3324         char *cp;
3325
3326         if (interactive) {
3327                 signal(SIGINT, SIG_DFL);
3328                 signal(SIGQUIT, SIG_DFL);
3329         }
3330         cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3331         prs(t->words[0]);
3332         prs(": ");
3333         err(cp);
3334         return 1;
3335 }
3336
3337 static int doumask(struct op *t)
3338 {
3339         int i, n;
3340         char *cp;
3341
3342         if ((cp = t->words[1]) == NULL) {
3343                 i = umask(0);
3344                 umask(i);
3345                 for (n = 3 * 4; (n -= 3) >= 0;)
3346                         putc('0' + ((i >> n) & 07), stderr);
3347                 putc('\n', stderr);
3348         } else {
3349                 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3350                         n = n * 8 + (*cp - '0');
3351                 umask(n);
3352         }
3353         return 0;
3354 }
3355
3356 static int doexec(struct op *t)
3357 {
3358         int i;
3359         jmp_buf ex;
3360         xint *ofail;
3361
3362         t->ioact = NULL;
3363         for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
3364         if (i == 0)
3365                 return 1;
3366         execflg = 1;
3367         ofail = failpt;
3368         if (setjmp(failpt = ex) == 0)
3369                 execute(t, NOPIPE, NOPIPE, FEXEC);
3370         failpt = ofail;
3371         execflg = 0;
3372         return 1;
3373 }
3374
3375 static int dodot(struct op *t)
3376 {
3377         int i;
3378         char *sp, *tp;
3379         char *cp;
3380         int maltmp;
3381
3382         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)));
3383
3384         if ((cp = t->words[1]) == NULL) {
3385                 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3386                 return 0;
3387         } else {
3388                 DBGPRINTF(("DODOT: cp is %s\n", cp));
3389         }
3390
3391         sp = any('/', cp) ? ":" : path->value;
3392
3393         DBGPRINTF(("DODOT: sp is %s,  e.linep is %s\n",
3394                            ((sp == NULL) ? "NULL" : sp),
3395                            ((e.linep == NULL) ? "NULL" : e.linep)));
3396
3397         while (*sp) {
3398                 tp = e.linep;
3399                 while (*sp && (*tp = *sp++) != ':')
3400                         tp++;
3401                 if (tp != e.linep)
3402                         *tp++ = '/';
3403
3404                 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3405
3406                 /* Original code */
3407                 if ((i = open(e.linep, 0)) >= 0) {
3408                         exstat = 0;
3409                         maltmp = remap(i);
3410                         DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3411
3412                         next(maltmp);           /* Basically a PUSHIO */
3413
3414                         DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3415
3416                         return exstat;
3417                 }
3418
3419         }                                                       /* While */
3420
3421         prs(cp);
3422         err(": not found");
3423
3424         return -1;
3425 }
3426
3427 static int dowait(struct op *t)
3428 {
3429         int i;
3430         char *cp;
3431
3432         if ((cp = t->words[1]) != NULL) {
3433                 i = getn(cp);
3434                 if (i == 0)
3435                         return 0;
3436         } else
3437                 i = -1;
3438         setstatus(waitfor(i, 1));
3439         return 0;
3440 }
3441
3442 static int doread(struct op *t)
3443 {
3444         char *cp, **wp;
3445         int nb = 0;
3446         int nl = 0;
3447
3448         if (t->words[1] == NULL) {
3449                 err("Usage: read name ...");
3450                 return 1;
3451         }
3452         for (wp = t->words + 1; *wp; wp++) {
3453                 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
3454                         if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
3455                                 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
3456                                 break;
3457                 *cp = 0;
3458                 if (nb <= 0)
3459                         break;
3460                 setval(lookup(*wp), e.linep);
3461         }
3462         return nb <= 0;
3463 }
3464
3465 static int doeval(struct op *t)
3466 {
3467         return RUN(awordlist, t->words + 1, wdchar);
3468 }
3469
3470 static int dotrap(struct op *t)
3471 {
3472         int n, i;
3473         int resetsig;
3474
3475         if (t->words[1] == NULL) {
3476                 for (i = 0; i <= _NSIG; i++)
3477                         if (trap[i]) {
3478                                 prn(i);
3479                                 prs(": ");
3480                                 prs(trap[i]);
3481                                 prs("\n");
3482                         }
3483                 return 0;
3484         }
3485         resetsig = isdigit(*t->words[1]);
3486         for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3487                 n = getsig(t->words[i]);
3488                 freecell(trap[n]);
3489                 trap[n] = 0;
3490                 if (!resetsig) {
3491                         if (*t->words[1] != '\0') {
3492                                 trap[n] = strsave(t->words[1], 0);
3493                                 setsig(n, sig);
3494                         } else
3495                                 setsig(n, SIG_IGN);
3496                 } else {
3497                         if (interactive)
3498                                 if (n == SIGINT)
3499                                         setsig(n, onintr);
3500                                 else
3501                                         setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3502                         else
3503                                 setsig(n, SIG_DFL);
3504                 }
3505         }
3506         return 0;
3507 }
3508
3509 static int getsig(char *s)
3510 {
3511         int n;
3512
3513         if ((n = getn(s)) < 0 || n > _NSIG) {
3514                 err("trap: bad signal number");
3515                 n = 0;
3516         }
3517         return n;
3518 }
3519
3520 static void setsig(int n, sighandler_t f)
3521 {
3522         if (n == 0)
3523                 return;
3524         if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3525                 ourtrap[n] = 1;
3526                 signal(n, f);
3527         }
3528 }
3529
3530 static int getn(char *as)
3531 {
3532         char *s;
3533         int n, m;
3534
3535         s = as;
3536         m = 1;
3537         if (*s == '-') {
3538                 m = -1;
3539                 s++;
3540         }
3541         for (n = 0; isdigit(*s); s++)
3542                 n = (n * 10) + (*s - '0');
3543         if (*s) {
3544                 prs(as);
3545                 err(": bad number");
3546         }
3547         return n * m;
3548 }
3549
3550 static int dobreak(struct op *t)
3551 {
3552         return brkcontin(t->words[1], 1);
3553 }
3554
3555 static int docontinue(struct op *t)
3556 {
3557         return brkcontin(t->words[1], 0);
3558 }
3559
3560 static int brkcontin(char *cp, int val)
3561 {
3562         struct brkcon *bc;
3563         int nl;
3564
3565         nl = cp == NULL ? 1 : getn(cp);
3566         if (nl <= 0)
3567                 nl = 999;
3568         do {
3569                 if ((bc = brklist) == NULL)
3570                         break;
3571                 brklist = bc->nextlev;
3572         } while (--nl);
3573         if (nl) {
3574                 err("bad break/continue level");
3575                 return 1;
3576         }
3577         isbreak = val;
3578         longjmp(bc->brkpt, 1);
3579         /* NOTREACHED */
3580 }
3581
3582 static int doexit(struct op *t)
3583 {
3584         char *cp;
3585
3586         execflg = 0;
3587         if ((cp = t->words[1]) != NULL)
3588                 setstatus(getn(cp));
3589
3590         DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3591
3592         leave();
3593         /* NOTREACHED */
3594         return 0;
3595 }
3596
3597 static int doexport(struct op *t)
3598 {
3599         rdexp(t->words + 1, export, EXPORT);
3600         return 0;
3601 }
3602
3603 static int doreadonly(struct op *t)
3604 {
3605         rdexp(t->words + 1, ronly, RONLY);
3606         return 0;
3607 }
3608
3609 static void rdexp(char **wp, void (*f) (struct var *), int key)
3610 {
3611         DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3612         DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3613
3614         if (*wp != NULL) {
3615                 for (; *wp != NULL; wp++) {
3616                         if (isassign(*wp)) {
3617                                 char *cp;
3618
3619                                 assign(*wp, COPYV);
3620                                 for (cp = *wp; *cp != '='; cp++);
3621                                 *cp = '\0';
3622                         }
3623                         if (checkname(*wp))
3624                                 (*f) (lookup(*wp));
3625                         else
3626                                 badid(*wp);
3627                 }
3628         } else
3629                 putvlist(key, 1);
3630 }
3631
3632 static void badid(char *s)
3633 {
3634         prs(s);
3635         err(": bad identifier");
3636 }
3637
3638 static int doset(struct op *t)
3639 {
3640         struct var *vp;
3641         char *cp;
3642         int n;
3643
3644         if ((cp = t->words[1]) == NULL) {
3645                 for (vp = vlist; vp; vp = vp->next)
3646                         varput(vp->name, 1);
3647                 return 0;
3648         }
3649         if (*cp == '-') {
3650                 /* bad: t->words++; */
3651                 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3652                 if (*++cp == 0)
3653                         flag['x'] = flag['v'] = 0;
3654                 else
3655                         for (; *cp; cp++)
3656                                 switch (*cp) {
3657                                 case 'e':
3658                                         if (!interactive)
3659                                                 flag['e']++;
3660                                         break;
3661
3662                                 default:
3663                                         if (*cp >= 'a' && *cp <= 'z')
3664                                                 flag[(int) *cp]++;
3665                                         break;
3666                                 }
3667                 setdash();
3668         }
3669         if (t->words[1]) {
3670                 t->words[0] = dolv[0];
3671                 for (n = 1; t->words[n]; n++)
3672                         setarea((char *) t->words[n], 0);
3673                 dolc = n - 1;
3674                 dolv = t->words;
3675                 setval(lookup("#"), putn(dolc));
3676                 setarea((char *) (dolv - 1), 0);
3677         }
3678         return 0;
3679 }
3680
3681 static void varput(char *s, int out)
3682 {
3683         if (isalnum(*s) || *s == '_') {
3684                 write(out, s, strlen(s));
3685                 write(out, "\n", 1);
3686         }
3687 }
3688
3689
3690 /*
3691  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3692  * This file contains code for the times builtin.
3693  */
3694 static int dotimes(struct op *t)
3695 {
3696         struct tms buf;
3697         long int clk_tck = sysconf(_SC_CLK_TCK);
3698
3699         times(&buf);
3700         printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3701                    (int) (buf.tms_utime / clk_tck / 60),
3702                    ((double) buf.tms_utime) / clk_tck,
3703                    (int) (buf.tms_stime / clk_tck / 60),
3704                    ((double) buf.tms_stime) / clk_tck,
3705                    (int) (buf.tms_cutime / clk_tck / 60),
3706                    ((double) buf.tms_cutime) / clk_tck,
3707                    (int) (buf.tms_cstime / clk_tck / 60),
3708                    ((double) buf.tms_cstime) / clk_tck);
3709         return 0;
3710 }
3711
3712
3713 static int (*inbuilt(char *s)) (struct op *) {
3714         const struct builtincmd *bp;
3715
3716         for (bp = builtincmds; bp->name != NULL; bp++)
3717                 if (strcmp(bp->name, s) == 0)
3718                         return bp->builtinfunc;
3719
3720         return NULL;
3721 }
3722
3723 /* -------- eval.c -------- */
3724
3725 /*
3726  * ${}
3727  * `command`
3728  * blank interpretation
3729  * quoting
3730  * glob
3731  */
3732
3733 static char **eval(char **ap, int f)
3734 {
3735         struct wdblock *wb;
3736         char **wp;
3737         char **wf;
3738         jmp_buf ev;
3739
3740 #if __GNUC__
3741         /* Avoid longjmp clobbering */
3742         (void) &wp;
3743         (void) &ap;
3744 #endif
3745
3746         DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3747
3748         wp = NULL;
3749         wb = NULL;
3750         wf = NULL;
3751         if (newenv(setjmp(errpt = ev)) == 0) {
3752                 while (*ap && isassign(*ap))
3753                         expand(*ap++, &wb, f & ~DOGLOB);
3754                 if (flag['k']) {
3755                         for (wf = ap; *wf; wf++) {
3756                                 if (isassign(*wf))
3757                                         expand(*wf, &wb, f & ~DOGLOB);
3758                         }
3759                 }
3760                 for (wb = addword((char *) 0, wb); *ap; ap++) {
3761                         if (!flag['k'] || !isassign(*ap))
3762                                 expand(*ap, &wb, f & ~DOKEY);
3763                 }
3764                 wb = addword((char *) 0, wb);
3765                 wp = getwords(wb);
3766                 quitenv();
3767         } else
3768                 gflg = 1;
3769
3770         return gflg ? (char **) NULL : wp;
3771 }
3772
3773 /*
3774  * Make the exported environment from the exported
3775  * names in the dictionary. Keyword assignments
3776  * will already have been done.
3777  */
3778 static char **makenv(int all, struct wdblock *wb)
3779 {
3780         struct var *vp;
3781
3782         DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3783
3784         for (vp = vlist; vp; vp = vp->next)
3785                 if (all || vp->status & EXPORT)
3786                         wb = addword(vp->name, wb);
3787         wb = addword((char *) 0, wb);
3788         return getwords(wb);
3789 }
3790
3791 static char *evalstr(char *cp, int f)
3792 {
3793         struct wdblock *wb;
3794
3795         DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3796
3797         wb = NULL;
3798         if (expand(cp, &wb, f)) {
3799                 if (wb == NULL || wb->w_nword == 0
3800                         || (cp = wb->w_words[0]) == NULL)
3801                         cp = "";
3802                 DELETE(wb);
3803         } else
3804                 cp = NULL;
3805         return cp;
3806 }
3807
3808 static int expand(char *cp, struct wdblock **wbp, int f)
3809 {
3810         jmp_buf ev;
3811
3812 #if __GNUC__
3813         /* Avoid longjmp clobbering */
3814         (void) &cp;
3815 #endif
3816
3817         DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3818
3819         gflg = 0;
3820
3821         if (cp == NULL)
3822                 return 0;
3823
3824         if (!anys("$`'\"", cp) &&
3825                 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
3826                 cp = strsave(cp, areanum);
3827                 if (f & DOTRIM)
3828                         unquote(cp);
3829                 *wbp = addword(cp, *wbp);
3830                 return 1;
3831         }
3832         if (newenv(setjmp(errpt = ev)) == 0) {
3833                 PUSHIO(aword, cp, strchar);
3834                 e.iobase = e.iop;
3835                 while ((cp = blank(f)) && gflg == 0) {
3836                         e.linep = cp;
3837                         cp = strsave(cp, areanum);
3838                         if ((f & DOGLOB) == 0) {
3839                                 if (f & DOTRIM)
3840                                         unquote(cp);
3841                                 *wbp = addword(cp, *wbp);
3842                         } else
3843                                 *wbp = glob(cp, *wbp);
3844                 }
3845                 quitenv();
3846         } else
3847                 gflg = 1;
3848         return gflg == 0;
3849 }
3850
3851 /*
3852  * Blank interpretation and quoting
3853  */
3854 static char *blank(int f)
3855 {
3856         int c, c1;
3857         char *sp;
3858         int scanequals, foundequals;
3859
3860         DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3861
3862         sp = e.linep;
3863         scanequals = f & DOKEY;
3864         foundequals = 0;
3865
3866   loop:
3867         switch (c = subgetc('"', foundequals)) {
3868         case 0:
3869                 if (sp == e.linep)
3870                         return 0;
3871                 *e.linep++ = 0;
3872                 return sp;
3873
3874         default:
3875                 if (f & DOBLANK && any(c, ifs->value))
3876                         goto loop;
3877                 break;
3878
3879         case '"':
3880         case '\'':
3881                 scanequals = 0;
3882                 if (INSUB())
3883                         break;
3884                 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3885                         if (c == 0)
3886                                 break;
3887                         if (c == '\'' || !any(c, "$`\""))
3888                                 c |= QUOTE;
3889                         *e.linep++ = c;
3890                 }
3891                 c = 0;
3892         }
3893         unget(c);
3894         if (!isalpha(c) && c != '_')
3895                 scanequals = 0;
3896         for (;;) {
3897                 c = subgetc('"', foundequals);
3898                 if (c == 0 ||
3899                         f & (DOBLANK && any(c, ifs->value)) ||
3900                         (!INSUB() && any(c, "\"'"))) {
3901                         scanequals = 0;
3902                         unget(c);
3903                         if (any(c, "\"'"))
3904                                 goto loop;
3905                         break;
3906                 }
3907                 if (scanequals) {
3908                         if (c == '=') {
3909                                 foundequals = 1;
3910                                 scanequals = 0;
3911                         } else if (!isalnum(c) && c != '_')
3912                                 scanequals = 0;
3913                 }
3914                 *e.linep++ = c;
3915         }
3916         *e.linep++ = 0;
3917         return sp;
3918 }
3919
3920 /*
3921  * Get characters, substituting for ` and $
3922  */
3923 static int subgetc(char ec, int quoted)
3924 {
3925         char c;
3926
3927         DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3928
3929   again:
3930         c = my_getc(ec);
3931         if (!INSUB() && ec != '\'') {
3932                 if (c == '`') {
3933                         if (grave(quoted) == 0)
3934                                 return 0;
3935                         e.iop->task = XGRAVE;
3936                         goto again;
3937                 }
3938                 if (c == '$' && (c = dollar(quoted)) == 0) {
3939                         e.iop->task = XDOLL;
3940                         goto again;
3941                 }
3942         }
3943         return c;
3944 }
3945
3946 /*
3947  * Prepare to generate the string returned by ${} substitution.
3948  */
3949 static int dollar(int quoted)
3950 {
3951         int otask;
3952         struct io *oiop;
3953         char *dolp;
3954         char *s, c, *cp = NULL;
3955         struct var *vp;
3956
3957         DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3958
3959         c = readc();
3960         s = e.linep;
3961         if (c != '{') {
3962                 *e.linep++ = c;
3963                 if (isalpha(c) || c == '_') {
3964                         while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3965                                 if (e.linep < elinep)
3966                                         *e.linep++ = c;
3967                         unget(c);
3968                 }
3969                 c = 0;
3970         } else {
3971                 oiop = e.iop;
3972                 otask = e.iop->task;
3973
3974                 e.iop->task = XOTHER;
3975                 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3976                         if (e.linep < elinep)
3977                                 *e.linep++ = c;
3978                 if (oiop == e.iop)
3979                         e.iop->task = otask;
3980                 if (c != '}') {
3981                         err("unclosed ${");
3982                         gflg++;
3983                         return c;
3984                 }
3985         }
3986         if (e.linep >= elinep) {
3987                 err("string in ${} too long");
3988                 gflg++;
3989                 e.linep -= 10;
3990         }
3991         *e.linep = 0;
3992         if (*s)
3993                 for (cp = s + 1; *cp; cp++)
3994                         if (any(*cp, "=-+?")) {
3995                                 c = *cp;
3996                                 *cp++ = 0;
3997                                 break;
3998                         }
3999         if (s[1] == 0 && (*s == '*' || *s == '@')) {
4000                 if (dolc > 1) {
4001                         /* currently this does not distinguish $* and $@ */
4002                         /* should check dollar */
4003                         e.linep = s;
4004                         PUSHIO(awordlist, dolv + 1, dolchar);
4005                         return 0;
4006                 } else {                                /* trap the nasty ${=} */
4007                         s[0] = '1';
4008                         s[1] = 0;
4009                 }
4010         }
4011         vp = lookup(s);
4012         if ((dolp = vp->value) == null) {
4013                 switch (c) {
4014                 case '=':
4015                         if (isdigit(*s)) {
4016                                 err("cannot use ${...=...} with $n");
4017                                 gflg++;
4018                                 break;
4019                         }
4020                         setval(vp, cp);
4021                         dolp = vp->value;
4022                         break;
4023
4024                 case '-':
4025                         dolp = strsave(cp, areanum);
4026                         break;
4027
4028                 case '?':
4029                         if (*cp == 0) {
4030                                 prs("missing value for ");
4031                                 err(s);
4032                         } else
4033                                 err(cp);
4034                         gflg++;
4035                         break;
4036                 }
4037         } else if (c == '+')
4038                 dolp = strsave(cp, areanum);
4039         if (flag['u'] && dolp == null) {
4040                 prs("unset variable: ");
4041                 err(s);
4042                 gflg++;
4043         }
4044         e.linep = s;
4045         PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4046         return 0;
4047 }
4048
4049 /*
4050  * Run the command in `...` and read its output.
4051  */
4052
4053 static int grave(int quoted)
4054 {
4055         char *cp;
4056         int i;
4057         int j;
4058         int pf[2];
4059         static char child_cmd[LINELIM];
4060         char *src;
4061         char *dest;
4062         int count;
4063         int ignore;
4064         int ignore_once;
4065         char *argument_list[4];
4066         struct wdblock *wb = NULL;
4067
4068 #if __GNUC__
4069         /* Avoid longjmp clobbering */
4070         (void) &cp;
4071 #endif
4072
4073         for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4074                 if (*cp == 0) {
4075                         err("no closing `");
4076                         return 0;
4077                 }
4078
4079         /* string copy with dollar expansion */
4080         src = e.iop->argp->aword;
4081         dest = child_cmd;
4082         count = 0;
4083         ignore = 0;
4084         ignore_once = 0;
4085         while ((*src != '`') && (count < LINELIM)) {
4086                 if (*src == '\'')
4087                         ignore = !ignore;
4088                 if (*src == '\\')
4089                         ignore_once = 1;
4090                 if (*src == '$' && !ignore && !ignore_once) {
4091                         struct var *vp;
4092                         char var_name[LINELIM];
4093                         char alt_value[LINELIM];
4094                         int var_index = 0;
4095                         int alt_index = 0;
4096                         char operator = 0;
4097                         int braces = 0;
4098                         char *value;
4099
4100                         src++;
4101                         if (*src == '{') {
4102                                 braces = 1;
4103                                 src++;
4104                         }
4105
4106                         var_name[var_index++] = *src++;
4107                         while (isalnum(*src) || *src=='_')
4108                                 var_name[var_index++] = *src++;
4109                         var_name[var_index] = 0;
4110
4111                         if (braces) {
4112                                 switch (*src) {
4113                                 case '}':
4114                                         break;
4115                                 case '-':
4116                                 case '=':
4117                                 case '+':
4118                                 case '?':
4119                                         operator = * src;
4120                                         break;
4121                                 default:
4122                                         err("unclosed ${\n");
4123                                         return 0;
4124                                 }
4125                                 if (operator) {
4126                                         src++;
4127                                         while (*src && (*src != '}')) {
4128                                                 alt_value[alt_index++] = *src++;
4129                                         }
4130                                         alt_value[alt_index] = 0;
4131                                         if (*src != '}') {
4132                                                 err("unclosed ${\n");
4133                                                 return 0;
4134                                         }
4135                                 }
4136                                 src++;
4137                         }
4138
4139                         if (isalpha(*var_name)) {
4140                                 /* let subshell handle it instead */
4141
4142                                 char *namep = var_name;
4143
4144                                 *dest++ = '$';
4145                                 if (braces)
4146                                         *dest++ = '{';
4147                                 while (*namep)
4148                                         *dest++ = *namep++;
4149                                 if (operator) {
4150                                         char *altp = alt_value;
4151                                         *dest++ = operator;
4152                                         while (*altp)
4153                                                 *dest++ = *altp++;
4154                                 }
4155                                 if (braces)
4156                                         *dest++ = '}';
4157
4158                                 wb = addword(lookup(var_name)->name, wb);
4159                         } else {
4160                                 /* expand */
4161
4162                                 vp = lookup(var_name);
4163                                 if (vp->value != null)
4164                                         value = (operator == '+') ?
4165                                                 alt_value : vp->value;
4166                                 else if (operator == '?') {
4167                                         err(alt_value);
4168                                         return 0;
4169                                 } else if (alt_index && (operator != '+')) {
4170                                         value = alt_value;
4171                                         if (operator == '=')
4172                                                 setval(vp, value);
4173                                 } else
4174                                         continue;
4175
4176                                 while (*value && (count < LINELIM)) {
4177                                         *dest++ = *value++;
4178                                         count++;
4179                                 }
4180                         }
4181                 } else {
4182                         *dest++ = *src++;
4183                         count++;
4184                         ignore_once = 0;
4185                 }
4186         }
4187         *dest = '\0';
4188
4189         if (openpipe(pf) < 0)
4190                 return 0;
4191
4192         while ((i = vfork()) == -1 && errno == EAGAIN);
4193
4194         DBGPRINTF3(("GRAVE: i is %p\n", io));
4195
4196         if (i < 0) {
4197                 closepipe(pf);
4198                 err((char *) bb_msg_memory_exhausted);
4199                 return 0;
4200         }
4201         if (i != 0) {
4202                 waitpid(i, NULL, 0);
4203                 e.iop->argp->aword = ++cp;
4204                 close(pf[1]);
4205                 PUSHIO(afile, remap(pf[0]),
4206                            (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4207                                                                                   gravechar));
4208                 return 1;
4209         }
4210         /* allow trapped signals */
4211         /* XXX - Maybe this signal stuff should go as well? */
4212         for (j = 0; j <= _NSIG; j++)
4213                 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4214                         signal(j, SIG_DFL);
4215
4216         dup2(pf[1], 1);
4217         closepipe(pf);
4218
4219         argument_list[0] = (char *) DEFAULT_SHELL;
4220         argument_list[1] = "-c";
4221         argument_list[2] = child_cmd;
4222         argument_list[3] = 0;
4223
4224         cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4225         prs(argument_list[0]);
4226         prs(": ");
4227         err(cp);
4228         _exit(1);
4229 }
4230
4231
4232 static char *unquote(char *as)
4233 {
4234         char *s;
4235
4236         if ((s = as) != NULL)
4237                 while (*s)
4238                         *s++ &= ~QUOTE;
4239         return as;
4240 }
4241
4242 /* -------- glob.c -------- */
4243
4244 /*
4245  * glob
4246  */
4247
4248 #define scopy(x) strsave((x), areanum)
4249 #define BLKSIZ  512
4250 #define NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4251
4252 static struct wdblock *cl, *nl;
4253 static char spcl[] = "[?*";
4254
4255 static struct wdblock *glob(char *cp, struct wdblock *wb)
4256 {
4257         int i;
4258         char *pp;
4259
4260         if (cp == 0)
4261                 return wb;
4262         i = 0;
4263         for (pp = cp; *pp; pp++)
4264                 if (any(*pp, spcl))
4265                         i++;
4266                 else if (!any(*pp & ~QUOTE, spcl))
4267                         *pp &= ~QUOTE;
4268         if (i != 0) {
4269                 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4270                          cl = nl) {
4271                         nl = newword(cl->w_nword * 2);
4272                         for (i = 0; i < cl->w_nword; i++) {     /* for each argument */
4273                                 for (pp = cl->w_words[i]; *pp; pp++)
4274                                         if (any(*pp, spcl)) {
4275                                                 globname(cl->w_words[i], pp);
4276                                                 break;
4277                                         }
4278                                 if (*pp == '\0')
4279                                         nl = addword(scopy(cl->w_words[i]), nl);
4280                         }
4281                         for (i = 0; i < cl->w_nword; i++)
4282                                 DELETE(cl->w_words[i]);
4283                         DELETE(cl);
4284                 }
4285                 for (i = 0; i < cl->w_nword; i++)
4286                         unquote(cl->w_words[i]);
4287                 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4288                 if (cl->w_nword) {
4289                         for (i = 0; i < cl->w_nword; i++)
4290                                 wb = addword(cl->w_words[i], wb);
4291                         DELETE(cl);
4292                         return wb;
4293                 }
4294         }
4295         wb = addword(unquote(cp), wb);
4296         return wb;
4297 }
4298
4299 static void globname(char *we, char *pp)
4300 {
4301         char *np, *cp;
4302         char *name, *gp, *dp;
4303         int k;
4304         DIR *dirp;
4305         struct dirent *de;
4306         char dname[NAME_MAX + 1];
4307         struct stat dbuf;
4308
4309         for (np = we; np != pp; pp--)
4310                 if (pp[-1] == '/')
4311                         break;
4312         for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4313                 *cp++ = *np++;
4314         *cp++ = '.';
4315         *cp = '\0';
4316         for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4317                 *cp++ = *np++;
4318         *cp = '\0';
4319         dirp = opendir(dp);
4320         if (dirp == 0) {
4321                 DELETE(dp);
4322                 DELETE(gp);
4323                 return;
4324         }
4325         dname[NAME_MAX] = '\0';
4326         while ((de = readdir(dirp)) != NULL) {
4327                 /* XXX Hmmm... What this could be? (abial) */
4328                 /*
4329                    if (ent[j].d_ino == 0)
4330                    continue;
4331                  */
4332                 strncpy(dname, de->d_name, NAME_MAX);
4333                 if (dname[0] == '.')
4334                         if (*gp != '.')
4335                                 continue;
4336                 for (k = 0; k < NAME_MAX; k++)
4337                         if (any(dname[k], spcl))
4338                                 dname[k] |= QUOTE;
4339                 if (gmatch(dname, gp)) {
4340                         name = generate(we, pp, dname, np);
4341                         if (*np && !anys(np, spcl)) {
4342                                 if (stat(name, &dbuf)) {
4343                                         DELETE(name);
4344                                         continue;
4345                                 }
4346                         }
4347                         nl = addword(name, nl);
4348                 }
4349         }
4350         closedir(dirp);
4351         DELETE(dp);
4352         DELETE(gp);
4353 }
4354
4355 /*
4356  * generate a pathname as below.
4357  * start..end1 / middle end
4358  * the slashes come for free
4359  */
4360 static char *generate(char *start1, char *end1, char *middle, char *end)
4361 {
4362         char *p;
4363         char *op, *xp;
4364
4365         p = op =
4366                 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
4367         for (xp = start1; xp != end1;)
4368                 *op++ = *xp++;
4369         for (xp = middle; (*op++ = *xp++) != '\0';);
4370         op--;
4371         for (xp = end; (*op++ = *xp++) != '\0';);
4372         return p;
4373 }
4374
4375 static int anyspcl(struct wdblock *wb)
4376 {
4377         int i;
4378         char **wd;
4379
4380         wd = wb->w_words;
4381         for (i = 0; i < wb->w_nword; i++)
4382                 if (anys(spcl, *wd++))
4383                         return 1;
4384         return 0;
4385 }
4386
4387 static int xstrcmp(char *p1, char *p2)
4388 {
4389         return strcmp(*(char **) p1, *(char **) p2);
4390 }
4391
4392 /* -------- word.c -------- */
4393
4394 static struct wdblock *newword(int nw)
4395 {
4396         struct wdblock *wb;
4397
4398         wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4399         wb->w_bsize = nw;
4400         wb->w_nword = 0;
4401         return wb;
4402 }
4403
4404 static struct wdblock *addword(char *wd, struct wdblock *wb)
4405 {
4406         struct wdblock *wb2;
4407         int nw;
4408
4409         if (wb == NULL)
4410                 wb = newword(NSTART);
4411         if ((nw = wb->w_nword) >= wb->w_bsize) {
4412                 wb2 = newword(nw * 2);
4413                 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4414                            nw * sizeof(char *));
4415                 wb2->w_nword = nw;
4416                 DELETE(wb);
4417                 wb = wb2;
4418         }
4419         wb->w_words[wb->w_nword++] = wd;
4420         return wb;
4421 }
4422
4423 static
4424 char **getwords(struct wdblock *wb)
4425 {
4426         char **wd;
4427         int nb;
4428
4429         if (wb == NULL)
4430                 return NULL;
4431         if (wb->w_nword == 0) {
4432                 DELETE(wb);
4433                 return NULL;
4434         }
4435         wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4436         memcpy((char *) wd, (char *) wb->w_words, nb);
4437         DELETE(wb);                                     /* perhaps should done by caller */
4438         return wd;
4439 }
4440
4441 static int (*func) (char *, char *);
4442 static int globv;
4443
4444 static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
4445 {
4446         func = a3;
4447         globv = a2;
4448         glob1(a0, a0 + a1 * a2);
4449 }
4450
4451 static void glob1(char *base, char *lim)
4452 {
4453         char *i, *j;
4454         int v2;
4455         char *lptr, *hptr;
4456         int c;
4457         unsigned n;
4458
4459
4460         v2 = globv;
4461
4462   top:
4463         if ((n = (int) (lim - base)) <= v2)
4464                 return;
4465         n = v2 * (n / (2 * v2));
4466         hptr = lptr = base + n;
4467         i = base;
4468         j = lim - v2;
4469         for (;;) {
4470                 if (i < lptr) {
4471                         if ((c = (*func) (i, lptr)) == 0) {
4472                                 glob2(i, lptr -= v2);
4473                                 continue;
4474                         }
4475                         if (c < 0) {
4476                                 i += v2;
4477                                 continue;
4478                         }
4479                 }
4480
4481           begin:
4482                 if (j > hptr) {
4483                         if ((c = (*func) (hptr, j)) == 0) {
4484                                 glob2(hptr += v2, j);
4485                                 goto begin;
4486                         }
4487                         if (c > 0) {
4488                                 if (i == lptr) {
4489                                         glob3(i, hptr += v2, j);
4490                                         i = lptr += v2;
4491                                         goto begin;
4492                                 }
4493                                 glob2(i, j);
4494                                 j -= v2;
4495                                 i += v2;
4496                                 continue;
4497                         }
4498                         j -= v2;
4499                         goto begin;
4500                 }
4501
4502
4503                 if (i == lptr) {
4504                         if (lptr - base >= lim - hptr) {
4505                                 glob1(hptr + v2, lim);
4506                                 lim = lptr;
4507                         } else {
4508                                 glob1(base, lptr);
4509                                 base = hptr + v2;
4510                         }
4511                         goto top;
4512                 }
4513
4514
4515                 glob3(j, lptr -= v2, i);
4516                 j = hptr -= v2;
4517         }
4518 }
4519
4520 static void glob2(char *i, char *j)
4521 {
4522         char *index1, *index2, c;
4523         int m;
4524
4525         m = globv;
4526         index1 = i;
4527         index2 = j;
4528         do {
4529                 c = *index1;
4530                 *index1++ = *index2;
4531                 *index2++ = c;
4532         } while (--m);
4533 }
4534
4535 static void glob3(char *i, char *j, char *k)
4536 {
4537         char *index1, *index2, *index3;
4538         int c;
4539         int m;
4540
4541         m = globv;
4542         index1 = i;
4543         index2 = j;
4544         index3 = k;
4545         do {
4546                 c = *index1;
4547                 *index1++ = *index3;
4548                 *index3++ = *index2;
4549                 *index2++ = c;
4550         } while (--m);
4551 }
4552
4553 /* -------- io.c -------- */
4554
4555 /*
4556  * shell IO
4557  */
4558
4559 static int my_getc(int ec)
4560 {
4561         int c;
4562
4563         if (e.linep > elinep) {
4564                 while ((c = readc()) != '\n' && c);
4565                 err("input line too long");
4566                 gflg++;
4567                 return c;
4568         }
4569         c = readc();
4570         if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
4571                 if (c == '\\') {
4572                         c = readc();
4573                         if (c == '\n' && ec != '\"')
4574                                 return my_getc(ec);
4575                         c |= QUOTE;
4576                 }
4577         }
4578         return c;
4579 }
4580
4581 static void unget(int c)
4582 {
4583         if (e.iop >= e.iobase)
4584                 e.iop->peekc = c;
4585 }
4586
4587 static int eofc(void)
4588 {
4589         return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4590 }
4591
4592 static int readc(void)
4593 {
4594         int c;
4595
4596         RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
4597
4598         for (; e.iop >= e.iobase; e.iop--) {
4599                 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
4600                 if ((c = e.iop->peekc) != '\0') {
4601                         e.iop->peekc = 0;
4602                         return c;
4603                 } else {
4604                         if (e.iop->prev != 0) {
4605                                 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4606                                         if (c == -1) {
4607                                                 e.iop++;
4608                                                 continue;
4609                                         }
4610                                         if (e.iop == iostack)
4611                                                 ioecho(c);
4612                                         return (e.iop->prev = c);
4613                                 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4614                                         e.iop->prev = 0;
4615                                         if (e.iop == iostack)
4616                                                 ioecho('\n');
4617                                         return '\n';
4618                                 }
4619                         }
4620                         if (e.iop->task == XIO) {
4621                                 if (multiline) {
4622                                         return e.iop->prev = 0;
4623                                 }
4624                                 if (interactive && e.iop == iostack + 1) {
4625 #ifdef CONFIG_FEATURE_COMMAND_EDITING
4626                                         current_prompt = prompt->value;
4627 #else
4628                                         prs(prompt->value);
4629 #endif
4630                                 }
4631                         }
4632                 }
4633
4634         }                                                       /* FOR */
4635
4636         if (e.iop >= iostack) {
4637                 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
4638                 return 0;
4639         }
4640
4641         DBGPRINTF(("READC: leave()...\n"));
4642         leave();
4643
4644         /* NOTREACHED */
4645         return 0;
4646 }
4647
4648 static void ioecho(char c)
4649 {
4650         if (flag['v'])
4651                 write(2, &c, sizeof c);
4652 }
4653
4654
4655 static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4656 {
4657         DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
4658                            argp->afid, e.iop));
4659
4660         /* Set env ptr for io source to next array spot and check for array overflow */
4661         if (++e.iop >= &iostack[NPUSH]) {
4662                 e.iop--;
4663                 err("Shell input nested too deeply");
4664                 gflg++;
4665                 return;
4666         }
4667
4668         /* We did not overflow the NPUSH array spots so setup data structs */
4669
4670         e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn;        /* Store data source func ptr */
4671
4672         if (argp->afid != AFID_NOBUF)
4673                 e.iop->argp = argp;
4674         else {
4675
4676                 e.iop->argp = ioargstack + (e.iop - iostack);   /* MAL - index into stack */
4677                 *e.iop->argp = *argp;   /* copy data from temp area into stack spot */
4678
4679                 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4680
4681                 if (e.iop == &iostack[0])
4682                         e.iop->argp->afbuf = &mainbuf;
4683                 else
4684                         e.iop->argp->afbuf = &sharedbuf;
4685
4686                 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4687                 /* This line appears to be active when running scripts from command line */
4688                 if ((isatty(e.iop->argp->afile) == 0)
4689                         && (e.iop == &iostack[0]
4690                                 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4691                         if (++bufid == AFID_NOBUF)      /* counter rollover check, AFID_NOBUF = 11111111  */
4692                                 bufid = AFID_ID;        /* AFID_ID = 0 */
4693
4694                         e.iop->argp->afid = bufid;      /* assign buffer id */
4695                 }
4696
4697                 DBGPRINTF(("PUSHIO: iostack %p,  e.iop %p, afbuf %p\n",
4698                                    iostack, e.iop, e.iop->argp->afbuf));
4699                 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
4700                                    &mainbuf, &sharedbuf, bufid, e.iop));
4701
4702         }
4703
4704         e.iop->prev = ~'\n';
4705         e.iop->peekc = 0;
4706         e.iop->xchar = 0;
4707         e.iop->nlcount = 0;
4708
4709         if (fn == filechar || fn == linechar)
4710                 e.iop->task = XIO;
4711         else if (fn == (int (*)(struct ioarg *)) gravechar
4712                          || fn == (int (*)(struct ioarg *)) qgravechar)
4713                 e.iop->task = XGRAVE;
4714         else
4715                 e.iop->task = XOTHER;
4716
4717         return;
4718 }
4719
4720 static struct io *setbase(struct io *ip)
4721 {
4722         struct io *xp;
4723
4724         xp = e.iobase;
4725         e.iobase = ip;
4726         return xp;
4727 }
4728
4729 /*
4730  * Input generating functions
4731  */
4732
4733 /*
4734  * Produce the characters of a string, then a newline, then EOF.
4735  */
4736 static int nlchar(struct ioarg *ap)
4737 {
4738         int c;
4739
4740         if (ap->aword == NULL)
4741                 return 0;
4742         if ((c = *ap->aword++) == 0) {
4743                 ap->aword = NULL;
4744                 return '\n';
4745         }
4746         return c;
4747 }
4748
4749 /*
4750  * Given a list of words, produce the characters
4751  * in them, with a space after each word.
4752  */
4753 static int wdchar(struct ioarg *ap)
4754 {
4755         char c;
4756         char **wl;
4757
4758         if ((wl = ap->awordlist) == NULL)
4759                 return 0;
4760         if (*wl != NULL) {
4761                 if ((c = *(*wl)++) != 0)
4762                         return c & 0177;
4763                 ap->awordlist++;
4764                 return ' ';
4765         }
4766         ap->awordlist = NULL;
4767         return '\n';
4768 }
4769
4770 /*
4771  * Return the characters of a list of words,
4772  * producing a space between them.
4773  */
4774 static int dolchar(struct ioarg *ap)
4775 {
4776         char *wp;
4777
4778         if ((wp = *ap->awordlist++) != NULL) {
4779                 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4780                 return -1;
4781         }
4782         return 0;
4783 }
4784
4785 static int xxchar(struct ioarg *ap)
4786 {
4787         int c;
4788
4789         if (ap->aword == NULL)
4790                 return 0;
4791         if ((c = *ap->aword++) == '\0') {
4792                 ap->aword = NULL;
4793                 return ' ';
4794         }
4795         return c;
4796 }
4797
4798 /*
4799  * Produce the characters from a single word (string).
4800  */
4801 static int strchar(struct ioarg *ap)
4802 {
4803         int c;
4804
4805         if (ap->aword == NULL || (c = *ap->aword++) == 0)
4806                 return 0;
4807         return c;
4808 }
4809
4810 /*
4811  * Produce quoted characters from a single word (string).
4812  */
4813 static int qstrchar(struct ioarg *ap)
4814 {
4815         int c;
4816
4817         if (ap->aword == NULL || (c = *ap->aword++) == 0)
4818                 return 0;
4819         return c | QUOTE;
4820 }
4821
4822 /*
4823  * Return the characters from a file.
4824  */
4825 static int filechar(struct ioarg *ap)
4826 {
4827         int i;
4828         char c;
4829         struct iobuf *bp = ap->afbuf;
4830
4831         if (ap->afid != AFID_NOBUF) {
4832                 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
4833
4834                         if (i)
4835                                 lseek(ap->afile, ap->afpos, SEEK_SET);
4836
4837                         i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4838
4839                         if (i <= 0) {
4840                                 closef(ap->afile);
4841                                 return 0;
4842                         }
4843
4844                         bp->id = ap->afid;
4845                         bp->ebufp = (bp->bufp = bp->buf) + i;
4846                 }
4847
4848                 ap->afpos++;
4849                 return *bp->bufp++ & 0177;
4850         }
4851 #ifdef CONFIG_FEATURE_COMMAND_EDITING
4852         if (interactive && isatty(ap->afile)) {
4853                 static char mycommand[BUFSIZ];
4854                 static int position = 0, size = 0;
4855
4856                 while (size == 0 || position >= size) {
4857                         cmdedit_read_input(current_prompt, mycommand);
4858                         size = strlen(mycommand);
4859                         position = 0;
4860                 }
4861                 c = mycommand[position];
4862                 position++;
4863                 return c;
4864         } else
4865 #endif
4866
4867         {
4868                 i = safe_read(ap->afile, &c, sizeof(c));
4869                 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4870         }
4871 }
4872
4873 /*
4874  * Return the characters from a here temp file.
4875  */
4876 static int herechar(struct ioarg *ap)
4877 {
4878         char c;
4879
4880
4881         if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4882                 close(ap->afile);
4883                 c = 0;
4884         }
4885         return c;
4886
4887 }
4888
4889 /*
4890  * Return the characters produced by a process (`...`).
4891  * Quote them if required, and remove any trailing newline characters.
4892  */
4893 static int gravechar(struct ioarg *ap, struct io *iop)
4894 {
4895         int c;
4896
4897         if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
4898                 c = ' ';
4899         return c;
4900 }
4901
4902 static int qgravechar(struct ioarg *ap, struct io *iop)
4903 {
4904         int c;
4905
4906         DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4907
4908         if (iop->xchar) {
4909                 if (iop->nlcount) {
4910                         iop->nlcount--;
4911                         return '\n' | QUOTE;
4912                 }
4913                 c = iop->xchar;
4914                 iop->xchar = 0;
4915         } else if ((c = filechar(ap)) == '\n') {
4916                 iop->nlcount = 1;
4917                 while ((c = filechar(ap)) == '\n')
4918                         iop->nlcount++;
4919                 iop->xchar = c;
4920                 if (c == 0)
4921                         return c;
4922                 iop->nlcount--;
4923                 c = '\n';
4924         }
4925         return c != 0 ? c | QUOTE : 0;
4926 }
4927
4928 /*
4929  * Return a single command (usually the first line) from a file.
4930  */
4931 static int linechar(struct ioarg *ap)
4932 {
4933         int c;
4934
4935         if ((c = filechar(ap)) == '\n') {
4936                 if (!multiline) {
4937                         closef(ap->afile);
4938                         ap->afile = -1;         /* illegal value */
4939                 }
4940         }
4941         return c;
4942 }
4943
4944 static void prs(const char *s)
4945 {
4946         if (*s)
4947                 write(2, s, strlen(s));
4948 }
4949
4950 static void prn(unsigned u)
4951 {
4952         prs(itoa(u));
4953 }
4954
4955 static void closef(int i)
4956 {
4957         if (i > 2)
4958                 close(i);
4959 }
4960
4961 static void closeall(void)
4962 {
4963         int u;
4964
4965         for (u = NUFILE; u < NOFILE;)
4966                 close(u++);
4967 }
4968
4969
4970 /*
4971  * remap fd into Shell's fd space
4972  */
4973 static int remap(int fd)
4974 {
4975         int i;
4976         int map[NOFILE];
4977         int newfd;
4978
4979
4980         DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
4981
4982         if (fd < e.iofd) {
4983                 for (i = 0; i < NOFILE; i++)
4984                         map[i] = 0;
4985
4986                 do {
4987                         map[fd] = 1;
4988                         newfd = dup(fd);
4989                         fd = newfd;
4990                 } while (fd >= 0 && fd < e.iofd);
4991
4992                 for (i = 0; i < NOFILE; i++)
4993                         if (map[i])
4994                                 close(i);
4995
4996                 if (fd < 0)
4997                         err("too many files open in shell");
4998         }
4999
5000         return fd;
5001 }
5002
5003 static int openpipe(int *pv)
5004 {
5005         int i;
5006
5007         if ((i = pipe(pv)) < 0)
5008                 err("can't create pipe - try again");
5009         return i;
5010 }
5011
5012 static void closepipe(int *pv)
5013 {
5014         if (pv != NULL) {
5015                 close(*pv++);
5016                 close(*pv);
5017         }
5018 }
5019
5020 /* -------- here.c -------- */
5021
5022 /*
5023  * here documents
5024  */
5025
5026 static void markhere(char *s, struct ioword *iop)
5027 {
5028         struct here *h, *lh;
5029
5030         DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
5031
5032         h = (struct here *) space(sizeof(struct here));
5033         if (h == 0)
5034                 return;
5035
5036         h->h_tag = evalstr(s, DOSUB);
5037         if (h->h_tag == 0)
5038                 return;
5039
5040         h->h_iop = iop;
5041         iop->io_name = 0;
5042         h->h_next = NULL;
5043         if (inhere == 0)
5044                 inhere = h;
5045         else
5046                 for (lh = inhere; lh != NULL; lh = lh->h_next)
5047                         if (lh->h_next == 0) {
5048                                 lh->h_next = h;
5049                                 break;
5050                         }
5051         iop->io_flag |= IOHERE | IOXHERE;
5052         for (s = h->h_tag; *s; s++)
5053                 if (*s & QUOTE) {
5054                         iop->io_flag &= ~IOXHERE;
5055                         *s &= ~QUOTE;
5056                 }
5057         h->h_dosub = iop->io_flag & IOXHERE;
5058 }
5059
5060 static void gethere(void)
5061 {
5062         struct here *h, *hp;
5063
5064         DBGPRINTF7(("GETHERE: enter...\n"));
5065
5066         /* Scan here files first leaving inhere list in place */
5067         for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5068                 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
5069
5070         /* Make inhere list active - keep list intact for scraphere */
5071         if (hp != NULL) {
5072                 hp->h_next = acthere;
5073                 acthere = inhere;
5074                 inhere = NULL;
5075         }
5076 }
5077
5078 static void readhere(char **name, char *s, int ec)
5079 {
5080         int tf;
5081         char tname[30] = ".msh_XXXXXX";
5082         int c;
5083         jmp_buf ev;
5084         char myline[LINELIM + 1];
5085         char *thenext;
5086
5087         DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
5088
5089         tf = mkstemp(tname);
5090         if (tf < 0)
5091                 return;
5092
5093         *name = strsave(tname, areanum);
5094         if (newenv(setjmp(errpt = ev)) != 0)
5095                 unlink(tname);
5096         else {
5097                 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
5098                 e.iobase = e.iop;
5099                 for (;;) {
5100                         if (interactive && e.iop <= iostack) {
5101 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5102                                 current_prompt = cprompt->value;
5103 #else
5104                                 prs(cprompt->value);
5105 #endif
5106                         }
5107                         thenext = myline;
5108                         while ((c = my_getc(ec)) != '\n' && c) {
5109                                 if (ec == '\'')
5110                                         c &= ~QUOTE;
5111                                 if (thenext >= &myline[LINELIM]) {
5112                                         c = 0;
5113                                         break;
5114                                 }
5115                                 *thenext++ = c;
5116                         }
5117                         *thenext = 0;
5118                         if (strcmp(s, myline) == 0 || c == 0)
5119                                 break;
5120                         *thenext++ = '\n';
5121                         write(tf, myline, (int) (thenext - myline));
5122                 }
5123                 if (c == 0) {
5124                         prs("here document `");
5125                         prs(s);
5126                         err("' unclosed");
5127                 }
5128                 quitenv();
5129         }
5130         close(tf);
5131 }
5132
5133 /*
5134  * open here temp file.
5135  * if unquoted here, expand here temp file into second temp file.
5136  */
5137 static int herein(char *hname, int xdoll)
5138 {
5139         int hf;
5140         int tf;
5141
5142 #if __GNUC__
5143         /* Avoid longjmp clobbering */
5144         (void) &tf;
5145 #endif
5146         if (hname == NULL)
5147                 return -1;
5148
5149         DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5150
5151         hf = open(hname, 0);
5152         if (hf < 0)
5153                 return -1;
5154
5155         if (xdoll) {
5156                 char c;
5157                 char tname[30] = ".msh_XXXXXX";
5158                 jmp_buf ev;
5159
5160                 tf = mkstemp(tname);
5161                 if (tf < 0)
5162                         return -1;
5163                 if (newenv(setjmp(errpt = ev)) == 0) {
5164                         PUSHIO(afile, hf, herechar);
5165                         setbase(e.iop);
5166                         while ((c = subgetc(0, 0)) != 0) {
5167                                 c &= ~QUOTE;
5168                                 write(tf, &c, sizeof c);
5169                         }
5170                         quitenv();
5171                 } else
5172                         unlink(tname);
5173                 close(tf);
5174                 tf = open(tname, 0);
5175                 unlink(tname);
5176                 return tf;
5177         } else
5178                 return hf;
5179 }
5180
5181 static void scraphere(void)
5182 {
5183         struct here *h;
5184
5185         DBGPRINTF7(("SCRAPHERE: enter...\n"));
5186
5187         for (h = inhere; h != NULL; h = h->h_next) {
5188                 if (h->h_iop && h->h_iop->io_name)
5189                         unlink(h->h_iop->io_name);
5190         }
5191         inhere = NULL;
5192 }
5193
5194 /* unlink here temp files before a freearea(area) */
5195 static void freehere(int area)
5196 {
5197         struct here *h, *hl;
5198
5199         DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5200
5201         hl = NULL;
5202         for (h = acthere; h != NULL; h = h->h_next)
5203                 if (getarea((char *) h) >= area) {
5204                         if (h->h_iop->io_name != NULL)
5205                                 unlink(h->h_iop->io_name);
5206                         if (hl == NULL)
5207                                 acthere = h->h_next;
5208                         else
5209                                 hl->h_next = h->h_next;
5210                 } else
5211                         hl = h;
5212 }
5213
5214
5215
5216 /*
5217  * Copyright (c) 1987,1997, Prentice Hall
5218  * All rights reserved.
5219  *
5220  * Redistribution and use of the MINIX operating system in source and
5221  * binary forms, with or without modification, are permitted provided
5222  * that the following conditions are met:
5223  *
5224  * Redistributions of source code must retain the above copyright
5225  * notice, this list of conditions and the following disclaimer.
5226  *
5227  * Redistributions in binary form must reproduce the above
5228  * copyright notice, this list of conditions and the following
5229  * disclaimer in the documentation and/or other materials provided
5230  * with the distribution.
5231  *
5232  * Neither the name of Prentice Hall nor the names of the software
5233  * authors or contributors may be used to endorse or promote
5234  * products derived from this software without specific prior
5235  * written permission.
5236  *
5237  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5238  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5239  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5240  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5241  * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5242  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5243  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5244  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5245  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5246  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5247  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5248  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5249  *
5250  */