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