Magellan Linux

Annotation of /tags/mkinitrd-6_1_11/busybox/shell/msh.c

Parent Directory Parent Directory | Revision Log Revision Log


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