Magellan Linux

Annotation of /tags/mkinitrd-6_2_0/shell/msh_unused.c

Parent Directory Parent Directory | Revision Log Revision Log


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