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