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