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