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