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