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