svlogd: fix compat problem: svlogd -tt should timestanp stderr too
[busybox.git] / shell / msh.c
blob7efd7f96e01f93eafb3533489ca430209db36548
1 /* vi: set sw=4 ts=4: */
2 /*
3 * Minix shell port for busybox
5 * This version of the Minix shell was adapted for use in busybox
6 * by Erik Andersen <andersen@codepoet.org>
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>
13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
16 #include <sys/times.h>
17 #include <setjmp.h>
19 #ifdef STANDALONE
20 # ifndef _GNU_SOURCE
21 # define _GNU_SOURCE
22 # endif
23 # include <sys/types.h>
24 # include <sys/stat.h>
25 # include <sys/wait.h>
26 # include <signal.h>
27 # include <stdio.h>
28 # include <stdlib.h>
29 # include <unistd.h>
30 # include <string.h>
31 # include <errno.h>
32 # include <dirent.h>
33 # include <fcntl.h>
34 # include <ctype.h>
35 # include <assert.h>
36 # define bb_dev_null "/dev/null"
37 # define DEFAULT_SHELL "/proc/self/exe"
38 # define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
39 # define bb_banner "busybox standalone"
40 # define ENABLE_FEATURE_SH_STANDALONE 0
41 # define bb_msg_memory_exhausted "memory exhausted"
42 # define xmalloc(size) malloc(size)
43 # define msh_main(argc,argv) main(argc,argv)
44 # define safe_read(fd,buf,count) read(fd,buf,count)
45 # define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46 # define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47 # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
48 static char *find_applet_by_name(const char *applet)
50 return NULL;
52 static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
54 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
61 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
68 return buf;
70 static char *itoa_to_buf(int n, char *buf, unsigned buflen)
72 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
77 return utoa_to_buf((unsigned)n, buf, buflen);
79 static char local_buf[12];
80 static char *itoa(int n)
82 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
83 return local_buf;
85 #else
86 # include "busybox.h"
87 extern char **environ;
88 #endif
90 /*#define MSHDEBUG 1*/
92 #ifdef MSHDEBUG
93 int mshdbg = MSHDEBUG;
95 #define DBGPRINTF(x) if (mshdbg>0) printf x
96 #define DBGPRINTF0(x) if (mshdbg>0) printf x
97 #define DBGPRINTF1(x) if (mshdbg>1) printf x
98 #define DBGPRINTF2(x) if (mshdbg>2) printf x
99 #define DBGPRINTF3(x) if (mshdbg>3) printf x
100 #define DBGPRINTF4(x) if (mshdbg>4) printf x
101 #define DBGPRINTF5(x) if (mshdbg>5) printf x
102 #define DBGPRINTF6(x) if (mshdbg>6) printf x
103 #define DBGPRINTF7(x) if (mshdbg>7) printf x
104 #define DBGPRINTF8(x) if (mshdbg>8) printf x
105 #define DBGPRINTF9(x) if (mshdbg>9) printf x
107 int mshdbg_rc = 0;
109 #define RCPRINTF(x) if (mshdbg_rc) printf x
111 #else
113 #define DBGPRINTF(x)
114 #define DBGPRINTF0(x) ((void)0)
115 #define DBGPRINTF1(x) ((void)0)
116 #define DBGPRINTF2(x) ((void)0)
117 #define DBGPRINTF3(x) ((void)0)
118 #define DBGPRINTF4(x) ((void)0)
119 #define DBGPRINTF5(x) ((void)0)
120 #define DBGPRINTF6(x) ((void)0)
121 #define DBGPRINTF7(x) ((void)0)
122 #define DBGPRINTF8(x) ((void)0)
123 #define DBGPRINTF9(x) ((void)0)
125 #define RCPRINTF(x) ((void)0)
127 #endif /* MSHDEBUG */
130 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
131 # define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132 # define DEFAULT_USER_PROMPT "\\u:\\w$ "
133 #else
134 # define DEFAULT_ROOT_PROMPT "# "
135 # define DEFAULT_USER_PROMPT "$ "
136 #endif
139 /* -------- sh.h -------- */
141 * shell
144 #define LINELIM 2100
145 #define NPUSH 8 /* limit to input nesting */
147 #undef NOFILE
148 #define NOFILE 20 /* Number of open files */
149 #define NUFILE 10 /* Number of user-accessible files */
150 #define FDBASE 10 /* First file usable by Shell */
153 * values returned by wait
155 #define WAITSIG(s) ((s) & 0177)
156 #define WAITVAL(s) (((s) >> 8) & 0377)
157 #define WAITCORE(s) (((s) & 0200) != 0)
160 * library and system definitions
162 typedef void xint; /* base type of jmp_buf, for not broken compilers */
165 * shell components
167 #define NOBLOCK ((struct op *)NULL)
168 #define NOWORD ((char *)NULL)
169 #define NOWORDS ((char **)NULL)
170 #define NOPIPE ((int *)NULL)
173 * redirection
175 struct ioword {
176 short io_unit; /* unit affected */
177 short io_flag; /* action (below) */
178 char *io_name; /* file name */
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 /* >&- */
189 #define IODEFAULT (-1) /* token for default IO unit */
193 * Description of a command or an operation on commands.
194 * Might eventually use a union.
196 struct op {
197 int type; /* operation type, see below */
198 char **words; /* arguments to a command */
199 struct ioword **ioact; /* IO actions (eg, < > >>) */
200 struct op *left;
201 struct op *right;
202 char *str; /* identifier for case and for */
205 #define TCOM 1 /* command */
206 #define TPAREN 2 /* (c-list) */
207 #define TPIPE 3 /* a | b */
208 #define TLIST 4 /* a [&;] b */
209 #define TOR 5 /* || */
210 #define TAND 6 /* && */
211 #define TFOR 7
212 #define TDO 8
213 #define TCASE 9
214 #define TIF 10
215 #define TWHILE 11
216 #define TUNTIL 12
217 #define TELIF 13
218 #define TPAT 14 /* pattern in case */
219 #define TBRACE 15 /* {c-list} */
220 #define TASYNC 16 /* c & */
221 /* Added to support "." file expansion */
222 #define TDOT 17
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",
246 #endif
249 * actions determining the environment of a process
251 #define FEXEC 1 /* execute without forking */
253 #define AREASIZE (90000)
256 * flags to control evaluation of words
258 #define DOSUB 1 /* interpret $, `, and quotes */
259 #define DOBLANK 2 /* perform blank interpretation */
260 #define DOGLOB 4 /* interpret [?* */
261 #define DOKEY 8 /* move words with `=' to 2nd arg. list */
262 #define DOTRIM 16 /* trim resulting string */
264 #define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
267 struct brkcon {
268 jmp_buf brkpt;
269 struct brkcon *nextlev;
274 * flags:
275 * -e: quit on error
276 * -k: look for name=value everywhere on command line
277 * -n: no execution
278 * -t: exit after reading and executing one command
279 * -v: echo as read
280 * -x: trace
281 * -u: unset variables net diagnostic
283 static char flags['z' - 'a' + 1] ALIGN1;
284 /* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
285 #define FLAG (flags - 'a')
287 /* moved to G: static char *trap[_NSIG + 1]; */
288 /* moved to G: static char ourtrap[_NSIG + 1]; */
289 static int trapset; /* trap pending */
291 static int yynerrs; /* yacc */
293 /* moved to G: static char line[LINELIM]; */
295 #if ENABLE_FEATURE_EDITING
296 static char *current_prompt;
297 static line_input_t *line_input_state;
298 #endif
302 * other functions
304 static const char *rexecve(char *c, char **v, char **envp);
305 static char *evalstr(char *cp, int f);
306 static char *putn(int n);
307 static char *unquote(char *as);
308 static int rlookup(char *n);
309 static struct wdblock *glob(char *cp, struct wdblock *wb);
310 static int my_getc(int ec);
311 static int subgetc(char ec, int quoted);
312 static char **makenv(int all, struct wdblock *wb);
313 static char **eval(char **ap, int f);
314 static int setstatus(int s);
315 static int waitfor(int lastpid, int canintr);
317 static void onintr(int s); /* SIGINT handler */
319 static int newenv(int f);
320 static void quitenv(void);
321 static void next(int f);
322 static void setdash(void);
323 static void onecommand(void);
324 static void runtrap(int i);
327 /* -------- area stuff -------- */
329 #define REGSIZE sizeof(struct region)
330 #define GROWBY (256)
331 /* #define SHRINKBY (64) */
332 #undef SHRINKBY
333 #define FREE (32767)
334 #define BUSY (0)
335 #define ALIGN (sizeof(int)-1)
338 struct region {
339 struct region *next;
340 int area;
344 /* -------- grammar stuff -------- */
345 typedef union {
346 char *cp;
347 char **wp;
348 int i;
349 struct op *o;
350 } YYSTYPE;
352 #define WORD 256
353 #define LOGAND 257
354 #define LOGOR 258
355 #define BREAK 259
356 #define IF 260
357 #define THEN 261
358 #define ELSE 262
359 #define ELIF 263
360 #define FI 264
361 #define CASE 265
362 #define ESAC 266
363 #define FOR 267
364 #define WHILE 268
365 #define UNTIL 269
366 #define DO 270
367 #define DONE 271
368 #define IN 272
369 /* Added for "." file expansion */
370 #define DOT 273
372 #define YYERRCODE 300
374 /* flags to yylex */
375 #define CONTIN 01 /* skip new lines to complete command */
377 static struct op *pipeline(int cf);
378 static struct op *andor(void);
379 static struct op *c_list(void);
380 static int synio(int cf);
381 static void musthave(int c, int cf);
382 static struct op *simple(void);
383 static struct op *nested(int type, int mark);
384 static struct op *command(int cf);
385 static struct op *dogroup(int onlydone);
386 static struct op *thenpart(void);
387 static struct op *elsepart(void);
388 static struct op *caselist(void);
389 static struct op *casepart(void);
390 static char **pattern(void);
391 static char **wordlist(void);
392 static struct op *list(struct op *t1, struct op *t2);
393 static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
394 static struct op *newtp(void);
395 static struct op *namelist(struct op *t);
396 static char **copyw(void);
397 static void word(char *cp);
398 static struct ioword **copyio(void);
399 static struct ioword *io(int u, int f, char *cp);
400 static int yylex(int cf);
401 static int collect(int c, int c1);
402 static int dual(int c);
403 static void diag(int ec);
404 static char *tree(unsigned size);
406 /* -------- var.h -------- */
408 struct var {
409 char *value;
410 char *name;
411 struct var *next;
412 char status;
415 #define COPYV 1 /* flag to setval, suggesting copy */
416 #define RONLY 01 /* variable is read-only */
417 #define EXPORT 02 /* variable is to be exported */
418 #define GETCELL 04 /* name & value space was got with getcell */
420 static int yyparse(void);
422 static int execute(struct op *t, int *pin, int *pout, int act);
425 #define AFID_NOBUF (~0)
426 #define AFID_ID 0
429 /* -------- io.h -------- */
430 /* io buffer */
431 struct iobuf {
432 unsigned id; /* buffer id */
433 char buf[512]; /* buffer */
434 char *bufp; /* pointer into buffer */
435 char *ebufp; /* pointer to end of buffer */
438 /* possible arguments to an IO function */
439 struct ioarg {
440 const char *aword;
441 char **awordlist;
442 int afile; /* file descriptor */
443 unsigned afid; /* buffer id */
444 long afpos; /* file position */
445 struct iobuf *afbuf; /* buffer for this file */
448 /* an input generator's state */
449 struct io {
450 int (*iofn) (struct ioarg *, struct io *);
451 struct ioarg *argp;
452 int peekc;
453 char prev; /* previous character read by readc() */
454 char nlcount; /* for `'s */
455 char xchar; /* for `'s */
456 char task; /* reason for pushed IO */
459 #define XOTHER 0 /* none of the below */
460 #define XDOLL 1 /* expanding ${} */
461 #define XGRAVE 2 /* expanding `'s */
462 #define XIO 3 /* file IO */
464 /* in substitution */
465 #define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
467 static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
468 /* moved to G: static struct ioarg ioargstack[NPUSH]; */
469 static struct io iostack[NPUSH];
470 /* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */
471 /* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */
472 static unsigned bufid = AFID_ID; /* buffer id counter */
474 #define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
478 * input generators for IO structure
480 static int nlchar(struct ioarg *ap);
481 static int strchar(struct ioarg *ap);
482 static int qstrchar(struct ioarg *ap);
483 static int filechar(struct ioarg *ap);
484 static int herechar(struct ioarg *ap);
485 static int linechar(struct ioarg *ap);
486 static int gravechar(struct ioarg *ap, struct io *iop);
487 static int qgravechar(struct ioarg *ap, struct io *iop);
488 static int dolchar(struct ioarg *ap);
489 static int wdchar(struct ioarg *ap);
490 static void scraphere(void);
491 static void freehere(int area);
492 static void gethere(void);
493 static void markhere(char *s, struct ioword *iop);
494 static int herein(char *hname, int xdoll);
495 static int run(struct ioarg *argp, int (*f) (struct ioarg *));
498 static int eofc(void);
499 static int readc(void);
500 static void unget(int c);
501 static void ioecho(char c);
505 * IO control
507 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
508 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
509 static int remap(int fd);
510 static int openpipe(int *pv);
511 static void closepipe(int *pv);
512 static struct io *setbase(struct io *ip);
514 /* -------- word.h -------- */
516 #define NSTART 16 /* default number of words to allow for initially */
518 struct wdblock {
519 short w_bsize;
520 short w_nword;
521 /* bounds are arbitrary */
522 char *w_words[1];
525 static struct wdblock *addword(char *wd, struct wdblock *wb);
526 static struct wdblock *newword(int nw);
527 static char **getwords(struct wdblock *wb);
529 /* -------- misc stuff -------- */
531 static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
532 static int iosetup(struct ioword *iop, int pipein, int pipeout);
533 static void brkset(struct brkcon *bc);
534 static int dolabel(struct op *t);
535 static int dohelp(struct op *t);
536 static int dochdir(struct op *t);
537 static int doshift(struct op *t);
538 static int dologin(struct op *t);
539 static int doumask(struct op *t);
540 static int doexec(struct op *t);
541 static int dodot(struct op *t);
542 static int dowait(struct op *t);
543 static int doread(struct op *t);
544 static int doeval(struct op *t);
545 static int dotrap(struct op *t);
546 static int getsig(char *s);
547 static void setsig(int n, sighandler_t f);
548 static int getn(char *as);
549 static int dobreak(struct op *t);
550 static int docontinue(struct op *t);
551 static int brkcontin(char *cp, int val);
552 static int doexit(struct op *t);
553 static int doexport(struct op *t);
554 static int doreadonly(struct op *t);
555 static void rdexp(char **wp, void (*f) (struct var *), int key);
556 static void badid(char *s);
557 static int doset(struct op *t);
558 static void varput(char *s, int out);
559 static int dotimes(struct op *t);
560 static int expand(const char *cp, struct wdblock **wbp, int f);
561 static char *blank(int f);
562 static int dollar(int quoted);
563 static int grave(int quoted);
564 static void globname(char *we, char *pp);
565 static char *generate(char *start1, char *end1, char *middle, char *end);
566 static int anyspcl(struct wdblock *wb);
567 static int xstrcmp(char *p1, char *p2);
568 static void glob0(char *a0, unsigned a1, int a2,
569 int (*a3) (char *, char *));
570 static void readhere(char **name, char *s, int ec);
571 static int xxchar(struct ioarg *ap);
573 struct here {
574 char *h_tag;
575 int h_dosub;
576 struct ioword *h_iop;
577 struct here *h_next;
580 static const char *const signame[] = {
581 "Signal 0",
582 "Hangup",
583 NULL, /* interrupt */
584 "Quit",
585 "Illegal instruction",
586 "Trace/BPT trap",
587 "Abort",
588 "Bus error",
589 "Floating Point Exception",
590 "Killed",
591 "SIGUSR1",
592 "SIGSEGV",
593 "SIGUSR2",
594 NULL, /* broken pipe */
595 "Alarm clock",
596 "Terminated"
600 struct res {
601 const char *r_name;
602 int r_val;
604 static const struct res restab[] = {
605 { "for" , FOR },
606 { "case" , CASE },
607 { "esac" , ESAC },
608 { "while", WHILE },
609 { "do" , DO },
610 { "done" , DONE },
611 { "if" , IF },
612 { "in" , IN },
613 { "then" , THEN },
614 { "else" , ELSE },
615 { "elif" , ELIF },
616 { "until", UNTIL },
617 { "fi" , FI },
618 { ";;" , BREAK },
619 { "||" , LOGOR },
620 { "&&" , LOGAND },
621 { "{" , '{' },
622 { "}" , '}' },
623 { "." , DOT },
624 { NULL , 0 },
627 struct builtincmd {
628 const char *name;
629 int (*builtinfunc)(struct op *t);
631 static const struct builtincmd builtincmds[] = {
632 { "." , dodot },
633 { ":" , dolabel },
634 { "break" , dobreak },
635 { "cd" , dochdir },
636 { "continue", docontinue },
637 { "eval" , doeval },
638 { "exec" , doexec },
639 { "exit" , doexit },
640 { "export" , doexport },
641 { "help" , dohelp },
642 { "login" , dologin },
643 { "newgrp" , dologin },
644 { "read" , doread },
645 { "readonly", doreadonly },
646 { "set" , doset },
647 { "shift" , doshift },
648 { "times" , dotimes },
649 { "trap" , dotrap },
650 { "umask" , doumask },
651 { "wait" , dowait },
652 { NULL , NULL },
655 static struct op *scantree(struct op *);
656 static struct op *dowholefile(int, int);
659 /* Globals */
660 static char **dolv;
661 static int dolc;
662 static int exstat;
663 static char gflg;
664 static int interactive; /* Is this an interactive shell */
665 static int execflg;
666 static int multiline; /* \n changed to ; */
667 static struct op *outtree; /* result from parser */
668 static xint *failpt;
669 static xint *errpt;
670 static struct brkcon *brklist;
671 static int isbreak;
672 static struct wdblock *wdlist;
673 static struct wdblock *iolist;
675 #ifdef MSHDEBUG
676 static struct var *mshdbg_var;
677 #endif
678 static struct var *vlist; /* dictionary */
679 static struct var *homedir; /* home directory */
680 static struct var *prompt; /* main prompt */
681 static struct var *cprompt; /* continuation prompt */
682 static struct var *path; /* search path for commands */
683 static struct var *shell; /* shell to interpret command files */
684 static struct var *ifs; /* field separators */
686 static int areanum; /* current allocation area */
687 static int intr; /* interrupt pending */
688 static int inparse;
689 static char *null = (char*)""; /* null value for variable */
690 static int heedint = 1; /* heed interrupt signals */
691 static void (*qflag)(int) = SIG_IGN;
692 static int startl;
693 static int peeksym;
694 static int nlseen;
695 static int iounit = IODEFAULT;
696 static YYSTYPE yylval;
697 static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
699 static struct here *inhere; /* list of hear docs while parsing */
700 static struct here *acthere; /* list of active here documents */
701 static struct region *areabot; /* bottom of area */
702 static struct region *areatop; /* top of area */
703 static struct region *areanxt; /* starting point of scan */
704 static void *brktop;
705 static void *brkaddr;
708 * parsing & execution environment
710 struct env {
711 char *linep;
712 struct io *iobase;
713 struct io *iop;
714 xint *errpt; /* void * */
715 int iofd;
716 struct env *oenv;
719 static struct env e = {
720 NULL /* set to line in main() */, /* linep: char ptr */
721 iostack, /* iobase: struct io ptr */
722 iostack - 1, /* iop: struct io ptr */
723 (xint *) NULL, /* errpt: void ptr for errors? */
724 FDBASE, /* iofd: file desc */
725 (struct env *) NULL /* oenv: struct env ptr */
729 struct globals {
730 char ourtrap[_NSIG + 1];
731 char *trap[_NSIG + 1];
732 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
733 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
734 struct ioarg ioargstack[NPUSH];
735 char filechar_cmdbuf[BUFSIZ];
736 char line[LINELIM];
737 char child_cmd[LINELIM];
740 #define G (*ptr_to_globals)
741 #define ourtrap (G.ourtrap )
742 #define trap (G.trap )
743 #define sharedbuf (G.sharedbuf )
744 #define mainbuf (G.mainbuf )
745 #define ioargstack (G.ioargstack )
746 #define filechar_cmdbuf (G.filechar_cmdbuf)
747 #define line (G.line )
748 #define child_cmd (G.child_cmd )
751 #ifdef MSHDEBUG
752 void print_t(struct op *t)
754 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
755 T_CMD_NAMES[t->type], t->words, t->ioact));
757 if (t->words) {
758 DBGPRINTF(("T: W1: %s", t->words[0]));
762 void print_tree(struct op *head)
764 if (head == NULL) {
765 DBGPRINTF(("PRINT_TREE: no tree\n"));
766 return;
769 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
770 head->right));
772 if (head->left)
773 print_tree(head->left);
775 if (head->right)
776 print_tree(head->right);
778 #endif /* MSHDEBUG */
782 * IO functions
784 static void prs(const char *s)
786 if (*s)
787 write(2, s, strlen(s));
790 static void prn(unsigned u)
792 prs(itoa(u));
795 static void echo(char **wp)
797 int i;
799 prs("+");
800 for (i = 0; wp[i]; i++) {
801 if (i)
802 prs(" ");
803 prs(wp[i]);
805 prs("\n");
808 static void closef(int i)
810 if (i > 2)
811 close(i);
814 static void closeall(void)
816 int u;
818 for (u = NUFILE; u < NOFILE;)
819 close(u++);
823 /* fail but return to process next command */
824 static void fail(void) ATTRIBUTE_NORETURN;
825 static void fail(void)
827 longjmp(failpt, 1);
828 /* NOTREACHED */
831 /* abort shell (or fail in subshell) */
832 static void leave(void) ATTRIBUTE_NORETURN;
833 static void leave(void)
835 DBGPRINTF(("LEAVE: leave called!\n"));
837 if (execflg)
838 fail();
839 scraphere();
840 freehere(1);
841 runtrap(0);
842 _exit(exstat);
843 /* NOTREACHED */
846 static void warn(const char *s)
848 if (*s) {
849 prs(s);
850 exstat = -1;
852 prs("\n");
853 if (FLAG['e'])
854 leave();
857 static void err(const char *s)
859 warn(s);
860 if (FLAG['n'])
861 return;
862 if (!interactive)
863 leave();
864 if (e.errpt)
865 longjmp(e.errpt, 1);
866 closeall();
867 e.iop = e.iobase = iostack;
871 /* -------- area.c -------- */
874 * All memory between (char *)areabot and (char *)(areatop+1) is
875 * exclusively administered by the area management routines.
876 * It is assumed that sbrk() and brk() manipulate the high end.
879 #define sbrk(X) ({ \
880 void * __q = (void *)-1; \
881 if (brkaddr + (int)(X) < brktop) { \
882 __q = brkaddr; \
883 brkaddr += (int)(X); \
885 __q; \
888 static void initarea(void)
890 brkaddr = xmalloc(AREASIZE);
891 brktop = brkaddr + AREASIZE;
893 while ((long) sbrk(0) & ALIGN)
894 sbrk(1);
895 areabot = (struct region *) sbrk(REGSIZE);
897 areabot->next = areabot;
898 areabot->area = BUSY;
899 areatop = areabot;
900 areanxt = areabot;
903 static char *getcell(unsigned nbytes)
905 int nregio;
906 struct region *p, *q;
907 int i;
909 if (nbytes == 0) {
910 puts("getcell(0)");
911 abort();
913 /* silly and defeats the algorithm */
915 * round upwards and add administration area
917 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
918 p = areanxt;
919 for (;;) {
920 if (p->area > areanum) {
922 * merge free cells
924 while ((q = p->next)->area > areanum && q != areanxt)
925 p->next = q->next;
927 * exit loop if cell big enough
929 if (q >= p + nregio)
930 goto found;
932 p = p->next;
933 if (p == areanxt)
934 break;
936 i = nregio >= GROWBY ? nregio : GROWBY;
937 p = (struct region *) sbrk(i * REGSIZE);
938 if (p == (struct region *) -1)
939 return NULL;
940 p--;
941 if (p != areatop) {
942 puts("not contig");
943 abort(); /* allocated areas are contiguous */
945 q = p + i;
946 p->next = q;
947 p->area = FREE;
948 q->next = areabot;
949 q->area = BUSY;
950 areatop = q;
951 found:
953 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
955 areanxt = p + nregio;
956 if (areanxt < q) {
958 * split into requested area and rest
960 if (areanxt + 1 > q) {
961 puts("OOM");
962 abort(); /* insufficient space left for admin */
964 areanxt->next = q;
965 areanxt->area = FREE;
966 p->next = areanxt;
968 p->area = areanum;
969 return (char *) (p + 1);
972 static void freecell(char *cp)
974 struct region *p;
976 p = (struct region *) cp;
977 if (p != NULL) {
978 p--;
979 if (p < areanxt)
980 areanxt = p;
981 p->area = FREE;
984 #define DELETE(obj) freecell((char *)obj)
986 static void freearea(int a)
988 struct region *p, *top;
990 top = areatop;
991 for (p = areabot; p != top; p = p->next)
992 if (p->area >= a)
993 p->area = FREE;
996 static void setarea(char *cp, int a)
998 struct region *p;
1000 p = (struct region *) cp;
1001 if (p != NULL)
1002 (p - 1)->area = a;
1005 static int getarea(char *cp)
1007 return ((struct region *) cp - 1)->area;
1010 static void garbage(void)
1012 struct region *p, *q, *top;
1014 top = areatop;
1015 for (p = areabot; p != top; p = p->next) {
1016 if (p->area > areanum) {
1017 while ((q = p->next)->area > areanum)
1018 p->next = q->next;
1019 areanxt = p;
1022 #ifdef SHRINKBY
1023 if (areatop >= q + SHRINKBY && q->area > areanum) {
1024 brk((char *) (q + 1));
1025 q->next = areabot;
1026 q->area = BUSY;
1027 areatop = q;
1029 #endif
1032 static char *space(int n)
1034 char *cp;
1036 cp = getcell(n);
1037 if (cp == NULL)
1038 err("out of string space");
1039 return cp;
1042 static char *strsave(const char *s, int a)
1044 char *cp;
1046 cp = space(strlen(s) + 1);
1047 if (cp == NULL) {
1048 // FIXME: I highly doubt this is good.
1049 return (char*)"";
1051 setarea(cp, a);
1052 strcpy(cp, s);
1053 return cp;
1057 /* -------- var.c -------- */
1059 static int eqname(const char *n1, const char *n2)
1061 for (; *n1 != '=' && *n1 != '\0'; n1++)
1062 if (*n2++ != *n1)
1063 return 0;
1064 return *n2 == '\0' || *n2 == '=';
1067 static const char *findeq(const char *cp)
1069 while (*cp != '\0' && *cp != '=')
1070 cp++;
1071 return cp;
1075 * Find the given name in the dictionary
1076 * and return its value. If the name was
1077 * not previously there, enter it now and
1078 * return a null value.
1080 static struct var *lookup(const char *n)
1082 // FIXME: dirty hack
1083 static struct var dummy;
1085 struct var *vp;
1086 const char *cp;
1087 char *xp;
1088 int c;
1090 if (isdigit(*n)) {
1091 dummy.name = (char*)n;
1092 for (c = 0; isdigit(*n) && c < 1000; n++)
1093 c = c * 10 + *n - '0';
1094 dummy.status = RONLY;
1095 dummy.value = (c <= dolc ? dolv[c] : null);
1096 return &dummy;
1099 for (vp = vlist; vp; vp = vp->next)
1100 if (eqname(vp->name, n))
1101 return vp;
1103 cp = findeq(n);
1104 vp = (struct var *) space(sizeof(*vp));
1105 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
1106 dummy.name = dummy.value = (char*)"";
1107 return &dummy;
1110 xp = vp->name;
1111 while ((*xp = *n++) != '\0' && *xp != '=')
1112 xp++;
1113 *xp++ = '=';
1114 *xp = '\0';
1115 setarea((char *) vp, 0);
1116 setarea((char *) vp->name, 0);
1117 vp->value = null;
1118 vp->next = vlist;
1119 vp->status = GETCELL;
1120 vlist = vp;
1121 return vp;
1125 * if name is not NULL, it must be
1126 * a prefix of the space `val',
1127 * and end with `='.
1128 * this is all so that exporting
1129 * values is reasonably painless.
1131 static void nameval(struct var *vp, const char *val, const char *name)
1133 const char *cp;
1134 char *xp;
1135 int fl;
1137 if (vp->status & RONLY) {
1138 xp = vp->name;
1139 while (*xp && *xp != '=')
1140 fputc(*xp++, stderr);
1141 err(" is read-only");
1142 return;
1144 fl = 0;
1145 if (name == NULL) {
1146 xp = space(strlen(vp->name) + strlen(val) + 2);
1147 if (xp == NULL)
1148 return;
1149 /* make string: name=value */
1150 setarea(xp, 0);
1151 name = xp;
1152 cp = vp->name;
1153 while ((*xp = *cp++) != '\0' && *xp != '=')
1154 xp++;
1155 *xp++ = '=';
1156 strcpy(xp, val);
1157 val = xp;
1158 fl = GETCELL;
1160 if (vp->status & GETCELL)
1161 freecell(vp->name); /* form new string `name=value' */
1162 vp->name = (char*)name;
1163 vp->value = (char*)val;
1164 vp->status |= fl;
1168 * give variable at `vp' the value `val'.
1170 static void setval(struct var *vp, const char *val)
1172 nameval(vp, val, NULL);
1175 static void export(struct var *vp)
1177 vp->status |= EXPORT;
1180 static void ronly(struct var *vp)
1182 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1183 vp->status |= RONLY;
1186 static int isassign(const char *s)
1188 unsigned char c;
1189 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1191 c = *s;
1192 /* no isalpha() - we shouldn't use locale */
1193 /* c | 0x20 - lowercase (Latin) letters */
1194 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1195 /* not letter */
1196 return 0;
1198 while (1) {
1199 c = *++s;
1200 if (c == '=')
1201 return 1;
1202 if (c == '\0')
1203 return 0;
1204 if (c != '_'
1205 && (unsigned)(c - '0') > 9 /* not number */
1206 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
1208 return 0;
1213 static int assign(const char *s, int cf)
1215 const char *cp;
1216 struct var *vp;
1218 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1220 if (!isalpha(*s) && *s != '_')
1221 return 0;
1222 for (cp = s; *cp != '='; cp++)
1223 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1224 return 0;
1225 vp = lookup(s);
1226 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1227 if (cf != COPYV)
1228 vp->status &= ~GETCELL;
1229 return 1;
1232 static int checkname(char *cp)
1234 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1236 if (!isalpha(*cp++) && *(cp - 1) != '_')
1237 return 0;
1238 while (*cp)
1239 if (!isalnum(*cp++) && *(cp - 1) != '_')
1240 return 0;
1241 return 1;
1244 static void putvlist(int f, int out)
1246 struct var *vp;
1248 for (vp = vlist; vp; vp = vp->next) {
1249 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1250 if (vp->status & EXPORT)
1251 write(out, "export ", 7);
1252 if (vp->status & RONLY)
1253 write(out, "readonly ", 9);
1254 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1255 write(out, "\n", 1);
1262 * trap handling
1264 static void sig(int i)
1266 trapset = i;
1267 signal(i, sig);
1270 static void runtrap(int i)
1272 char *trapstr;
1274 trapstr = trap[i];
1275 if (trapstr == NULL)
1276 return;
1278 if (i == 0)
1279 trap[i] = NULL;
1281 RUN(aword, trapstr, nlchar);
1285 static void setdash(void)
1287 char *cp;
1288 int c;
1289 char m['z' - 'a' + 1];
1291 cp = m;
1292 for (c = 'a'; c <= 'z'; c++)
1293 if (FLAG[c])
1294 *cp++ = c;
1295 *cp = '\0';
1296 setval(lookup("-"), m);
1299 static int newfile(char *s)
1301 int f;
1303 DBGPRINTF7(("NEWFILE: opening %s\n", s));
1305 f = 0;
1306 if (NOT_LONE_DASH(s)) {
1307 DBGPRINTF(("NEWFILE: s is %s\n", s));
1308 f = open(s, O_RDONLY);
1309 if (f < 0) {
1310 prs(s);
1311 err(": cannot open");
1312 return 1;
1316 next(remap(f));
1317 return 0;
1321 struct op *scantree(struct op *head)
1323 struct op *dotnode;
1325 if (head == NULL)
1326 return NULL;
1328 if (head->left != NULL) {
1329 dotnode = scantree(head->left);
1330 if (dotnode)
1331 return dotnode;
1334 if (head->right != NULL) {
1335 dotnode = scantree(head->right);
1336 if (dotnode)
1337 return dotnode;
1340 if (head->words == NULL)
1341 return NULL;
1343 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1345 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
1346 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1347 return head;
1350 return NULL;
1354 static void onecommand(void)
1356 int i;
1357 jmp_buf m1;
1359 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
1361 while (e.oenv)
1362 quitenv();
1364 areanum = 1;
1365 freehere(areanum);
1366 freearea(areanum);
1367 garbage();
1368 wdlist = 0;
1369 iolist = 0;
1370 e.errpt = 0;
1371 e.linep = line;
1372 yynerrs = 0;
1373 multiline = 0;
1374 inparse = 1;
1375 intr = 0;
1376 execflg = 0;
1378 failpt = m1;
1379 setjmp(failpt); /* Bruce Evans' fix */
1380 failpt = m1;
1381 if (setjmp(failpt) || yyparse() || intr) {
1382 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1384 while (e.oenv)
1385 quitenv();
1386 scraphere();
1387 if (!interactive && intr)
1388 leave();
1389 inparse = 0;
1390 intr = 0;
1391 return;
1394 inparse = 0;
1395 brklist = 0;
1396 intr = 0;
1397 execflg = 0;
1399 if (!FLAG['n']) {
1400 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1401 outtree));
1402 execute(outtree, NOPIPE, NOPIPE, 0);
1405 if (!interactive && intr) {
1406 execflg = 0;
1407 leave();
1410 i = trapset;
1411 if (i != 0) {
1412 trapset = 0;
1413 runtrap(i);
1417 static int newenv(int f)
1419 struct env *ep;
1421 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1423 if (f) {
1424 quitenv();
1425 return 1;
1428 ep = (struct env *) space(sizeof(*ep));
1429 if (ep == NULL) {
1430 while (e.oenv)
1431 quitenv();
1432 fail();
1434 *ep = e;
1435 e.oenv = ep;
1436 e.errpt = errpt;
1438 return 0;
1441 static void quitenv(void)
1443 struct env *ep;
1444 int fd;
1446 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
1448 ep = e.oenv;
1449 if (ep != NULL) {
1450 fd = e.iofd;
1451 e = *ep;
1452 /* should close `'d files */
1453 DELETE(ep);
1454 while (--fd >= e.iofd)
1455 close(fd);
1460 * Is character c in s?
1462 static int any(int c, const char *s)
1464 while (*s)
1465 if (*s++ == c)
1466 return 1;
1467 return 0;
1471 * Is any character from s1 in s2?
1473 static int anys(const char *s1, const char *s2)
1475 while (*s1)
1476 if (any(*s1++, s2))
1477 return 1;
1478 return 0;
1481 static char *putn(int n)
1483 return itoa(n);
1486 static void next(int f)
1488 PUSHIO(afile, f, filechar);
1491 static void onintr(int s) /* ANSI C requires a parameter */
1493 signal(SIGINT, onintr);
1494 intr = 1;
1495 if (interactive) {
1496 if (inparse) {
1497 prs("\n");
1498 fail();
1500 } else if (heedint) {
1501 execflg = 0;
1502 leave();
1507 /* -------- gmatch.c -------- */
1509 * int gmatch(string, pattern)
1510 * char *string, *pattern;
1512 * Match a pattern as in sh(1).
1515 #define CMASK 0377
1516 #define QUOTE 0200
1517 #define QMASK (CMASK & ~QUOTE)
1518 #define NOT '!' /* might use ^ */
1520 static const char *cclass(const char *p, int sub)
1522 int c, d, not, found;
1524 not = (*p == NOT);
1525 if (not != 0)
1526 p++;
1527 found = not;
1528 do {
1529 if (*p == '\0')
1530 return NULL;
1531 c = *p & CMASK;
1532 if (p[1] == '-' && p[2] != ']') {
1533 d = p[2] & CMASK;
1534 p++;
1535 } else
1536 d = c;
1537 if (c == sub || (c <= sub && sub <= d))
1538 found = !not;
1539 } while (*++p != ']');
1540 return found ? p + 1 : NULL;
1543 static int gmatch(const char *s, const char *p)
1545 int sc, pc;
1547 if (s == NULL || p == NULL)
1548 return 0;
1550 while ((pc = *p++ & CMASK) != '\0') {
1551 sc = *s++ & QMASK;
1552 switch (pc) {
1553 case '[':
1554 p = cclass(p, sc);
1555 if (p == NULL)
1556 return 0;
1557 break;
1559 case '?':
1560 if (sc == 0)
1561 return 0;
1562 break;
1564 case '*':
1565 s--;
1566 do {
1567 if (*p == '\0' || gmatch(s, p))
1568 return 1;
1569 } while (*s++ != '\0');
1570 return 0;
1572 default:
1573 if (sc != (pc & ~QUOTE))
1574 return 0;
1577 return *s == '\0';
1581 /* -------- csyn.c -------- */
1583 * shell: syntax (C version)
1586 static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1587 static void yyerror(const char *s)
1589 yynerrs++;
1590 if (interactive && e.iop <= iostack) {
1591 multiline = 0;
1592 while (eofc() == 0 && yylex(0) != '\n');
1594 err(s);
1595 fail();
1598 static void zzerr(void) ATTRIBUTE_NORETURN;
1599 static void zzerr(void)
1601 yyerror("syntax error");
1604 int yyparse(void)
1606 DBGPRINTF7(("YYPARSE: enter...\n"));
1608 startl = 1;
1609 peeksym = 0;
1610 yynerrs = 0;
1611 outtree = c_list();
1612 musthave('\n', 0);
1613 return (yynerrs != 0);
1616 static struct op *pipeline(int cf)
1618 struct op *t, *p;
1619 int c;
1621 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1623 t = command(cf);
1625 DBGPRINTF9(("PIPELINE: t=%p\n", t));
1627 if (t != NULL) {
1628 while ((c = yylex(0)) == '|') {
1629 p = command(CONTIN);
1630 if (p == NULL) {
1631 DBGPRINTF8(("PIPELINE: error!\n"));
1632 zzerr();
1635 if (t->type != TPAREN && t->type != TCOM) {
1636 /* shell statement */
1637 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1640 t = block(TPIPE, t, p, NOWORDS);
1642 peeksym = c;
1645 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
1646 return t;
1649 static struct op *andor(void)
1651 struct op *t, *p;
1652 int c;
1654 DBGPRINTF7(("ANDOR: enter...\n"));
1656 t = pipeline(0);
1658 DBGPRINTF9(("ANDOR: t=%p\n", t));
1660 if (t != NULL) {
1661 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1662 p = pipeline(CONTIN);
1663 if (p == NULL) {
1664 DBGPRINTF8(("ANDOR: error!\n"));
1665 zzerr();
1668 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1669 } /* WHILE */
1671 peeksym = c;
1674 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
1675 return t;
1678 static struct op *c_list(void)
1680 struct op *t, *p;
1681 int c;
1683 DBGPRINTF7(("C_LIST: enter...\n"));
1685 t = andor();
1687 if (t != NULL) {
1688 peeksym = yylex(0);
1689 if (peeksym == '&')
1690 t = block(TASYNC, t, NOBLOCK, NOWORDS);
1692 while ((c = yylex(0)) == ';' || c == '&'
1693 || (multiline && c == '\n')) {
1695 p = andor();
1696 if (p== NULL)
1697 return t;
1699 peeksym = yylex(0);
1700 if (peeksym == '&')
1701 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1703 t = list(t, p);
1704 } /* WHILE */
1706 peeksym = c;
1708 /* IF */
1709 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1710 return t;
1713 static int synio(int cf)
1715 struct ioword *iop;
1716 int i;
1717 int c;
1719 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1721 c = yylex(cf);
1722 if (c != '<' && c != '>') {
1723 peeksym = c;
1724 return 0;
1727 i = yylval.i;
1728 musthave(WORD, 0);
1729 iop = io(iounit, i, yylval.cp);
1730 iounit = IODEFAULT;
1732 if (i & IOHERE)
1733 markhere(yylval.cp, iop);
1735 DBGPRINTF7(("SYNIO: returning 1\n"));
1736 return 1;
1739 static void musthave(int c, int cf)
1741 peeksym = yylex(cf);
1742 if (peeksym != c) {
1743 DBGPRINTF7(("MUSTHAVE: error!\n"));
1744 zzerr();
1747 peeksym = 0;
1750 static struct op *simple(void)
1752 struct op *t;
1754 t = NULL;
1755 for (;;) {
1756 switch (peeksym = yylex(0)) {
1757 case '<':
1758 case '>':
1759 (void) synio(0);
1760 break;
1762 case WORD:
1763 if (t == NULL) {
1764 t = newtp();
1765 t->type = TCOM;
1767 peeksym = 0;
1768 word(yylval.cp);
1769 break;
1771 default:
1772 return t;
1777 static struct op *nested(int type, int mark)
1779 struct op *t;
1781 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1783 multiline++;
1784 t = c_list();
1785 musthave(mark, 0);
1786 multiline--;
1787 return block(type, t, NOBLOCK, NOWORDS);
1790 static struct op *command(int cf)
1792 struct op *t;
1793 struct wdblock *iosave;
1794 int c;
1796 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1798 iosave = iolist;
1799 iolist = NULL;
1801 if (multiline)
1802 cf |= CONTIN;
1804 while (synio(cf))
1805 cf = 0;
1807 c = yylex(cf);
1809 switch (c) {
1810 default:
1811 peeksym = c;
1812 t = simple();
1813 if (t == NULL) {
1814 if (iolist == NULL)
1815 return NULL;
1816 t = newtp();
1817 t->type = TCOM;
1819 break;
1821 case '(':
1822 t = nested(TPAREN, ')');
1823 break;
1825 case '{':
1826 t = nested(TBRACE, '}');
1827 break;
1829 case FOR:
1830 t = newtp();
1831 t->type = TFOR;
1832 musthave(WORD, 0);
1833 startl = 1;
1834 t->str = yylval.cp;
1835 multiline++;
1836 t->words = wordlist();
1837 c = yylex(0);
1838 if (c != '\n' && c != ';')
1839 peeksym = c;
1840 t->left = dogroup(0);
1841 multiline--;
1842 break;
1844 case WHILE:
1845 case UNTIL:
1846 multiline++;
1847 t = newtp();
1848 t->type = c == WHILE ? TWHILE : TUNTIL;
1849 t->left = c_list();
1850 t->right = dogroup(1);
1851 t->words = NULL;
1852 multiline--;
1853 break;
1855 case CASE:
1856 t = newtp();
1857 t->type = TCASE;
1858 musthave(WORD, 0);
1859 t->str = yylval.cp;
1860 startl++;
1861 multiline++;
1862 musthave(IN, CONTIN);
1863 startl++;
1865 t->left = caselist();
1867 musthave(ESAC, 0);
1868 multiline--;
1869 break;
1871 case IF:
1872 multiline++;
1873 t = newtp();
1874 t->type = TIF;
1875 t->left = c_list();
1876 t->right = thenpart();
1877 musthave(FI, 0);
1878 multiline--;
1879 break;
1881 case DOT:
1882 t = newtp();
1883 t->type = TDOT;
1885 musthave(WORD, 0); /* gets name of file */
1886 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1888 word(yylval.cp); /* add word to wdlist */
1889 word(NOWORD); /* terminate wdlist */
1890 t->words = copyw(); /* dup wdlist */
1891 break;
1895 while (synio(0));
1897 t = namelist(t);
1898 iolist = iosave;
1900 DBGPRINTF(("COMMAND: returning %p\n", t));
1902 return t;
1905 static struct op *dowholefile(int type, int mark)
1907 struct op *t;
1909 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1911 multiline++;
1912 t = c_list();
1913 multiline--;
1914 t = block(type, t, NOBLOCK, NOWORDS);
1915 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
1916 return t;
1919 static struct op *dogroup(int onlydone)
1921 int c;
1922 struct op *mylist;
1924 c = yylex(CONTIN);
1925 if (c == DONE && onlydone)
1926 return NULL;
1927 if (c != DO)
1928 zzerr();
1929 mylist = c_list();
1930 musthave(DONE, 0);
1931 return mylist;
1934 static struct op *thenpart(void)
1936 int c;
1937 struct op *t;
1939 c = yylex(0);
1940 if (c != THEN) {
1941 peeksym = c;
1942 return NULL;
1944 t = newtp();
1945 t->type = 0;
1946 t->left = c_list();
1947 if (t->left == NULL)
1948 zzerr();
1949 t->right = elsepart();
1950 return t;
1953 static struct op *elsepart(void)
1955 int c;
1956 struct op *t;
1958 switch (c = yylex(0)) {
1959 case ELSE:
1960 t = c_list();
1961 if (t == NULL)
1962 zzerr();
1963 return t;
1965 case ELIF:
1966 t = newtp();
1967 t->type = TELIF;
1968 t->left = c_list();
1969 t->right = thenpart();
1970 return t;
1972 default:
1973 peeksym = c;
1974 return NULL;
1978 static struct op *caselist(void)
1980 struct op *t;
1982 t = NULL;
1983 while ((peeksym = yylex(CONTIN)) != ESAC) {
1984 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
1985 t = list(t, casepart());
1988 DBGPRINTF(("CASELIST, returning t=%p\n", t));
1989 return t;
1992 static struct op *casepart(void)
1994 struct op *t;
1996 DBGPRINTF7(("CASEPART: enter...\n"));
1998 t = newtp();
1999 t->type = TPAT;
2000 t->words = pattern();
2001 musthave(')', 0);
2002 t->left = c_list();
2003 peeksym = yylex(CONTIN);
2004 if (peeksym != ESAC)
2005 musthave(BREAK, CONTIN);
2007 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
2009 return t;
2012 static char **pattern(void)
2014 int c, cf;
2016 cf = CONTIN;
2017 do {
2018 musthave(WORD, cf);
2019 word(yylval.cp);
2020 cf = 0;
2021 c = yylex(0);
2022 } while (c == '|');
2023 peeksym = c;
2024 word(NOWORD);
2026 return copyw();
2029 static char **wordlist(void)
2031 int c;
2033 c = yylex(0);
2034 if (c != IN) {
2035 peeksym = c;
2036 return NULL;
2038 startl = 0;
2039 while ((c = yylex(0)) == WORD)
2040 word(yylval.cp);
2041 word(NOWORD);
2042 peeksym = c;
2043 return copyw();
2047 * supporting functions
2049 static struct op *list(struct op *t1, struct op *t2)
2051 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
2053 if (t1 == NULL)
2054 return t2;
2055 if (t2 == NULL)
2056 return t1;
2058 return block(TLIST, t1, t2, NOWORDS);
2061 static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
2063 struct op *t;
2065 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2067 t = newtp();
2068 t->type = type;
2069 t->left = t1;
2070 t->right = t2;
2071 t->words = wp;
2073 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
2074 t2));
2076 return t;
2079 /* See if given string is a shell multiline (FOR, IF, etc) */
2080 static int rlookup(char *n)
2082 const struct res *rp;
2084 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2086 for (rp = restab; rp->r_name; rp++)
2087 if (strcmp(rp->r_name, n) == 0) {
2088 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2089 return rp->r_val; /* Return numeric code for shell multiline */
2092 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2093 return 0; /* Not a shell multiline */
2096 static struct op *newtp(void)
2098 struct op *t;
2100 t = (struct op *) tree(sizeof(*t));
2101 t->type = 0;
2102 t->words = NULL;
2103 t->ioact = NULL;
2104 t->left = NULL;
2105 t->right = NULL;
2106 t->str = NULL;
2108 DBGPRINTF3(("NEWTP: allocated %p\n", t));
2110 return t;
2113 static struct op *namelist(struct op *t)
2115 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
2116 T_CMD_NAMES[t->type], iolist));
2118 if (iolist) {
2119 iolist = addword((char *) NULL, iolist);
2120 t->ioact = copyio();
2121 } else
2122 t->ioact = NULL;
2124 if (t->type != TCOM) {
2125 if (t->type != TPAREN && t->ioact != NULL) {
2126 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2127 t->ioact = t->left->ioact;
2128 t->left->ioact = NULL;
2130 return t;
2133 word(NOWORD);
2134 t->words = copyw();
2136 return t;
2139 static char **copyw(void)
2141 char **wd;
2143 wd = getwords(wdlist);
2144 wdlist = 0;
2145 return wd;
2148 static void word(char *cp)
2150 wdlist = addword(cp, wdlist);
2153 static struct ioword **copyio(void)
2155 struct ioword **iop;
2157 iop = (struct ioword **) getwords(iolist);
2158 iolist = 0;
2159 return iop;
2162 static struct ioword *io(int u, int f, char *cp)
2164 struct ioword *iop;
2166 iop = (struct ioword *) tree(sizeof(*iop));
2167 iop->io_unit = u;
2168 iop->io_flag = f;
2169 iop->io_name = cp;
2170 iolist = addword((char *) iop, iolist);
2171 return iop;
2174 static int yylex(int cf)
2176 int c, c1;
2177 int atstart;
2179 c = peeksym;
2180 if (c > 0) {
2181 peeksym = 0;
2182 if (c == '\n')
2183 startl = 1;
2184 return c;
2187 nlseen = 0;
2188 atstart = startl;
2189 startl = 0;
2190 yylval.i = 0;
2191 e.linep = line;
2193 /* MALAMO */
2194 line[LINELIM - 1] = '\0';
2196 loop:
2197 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2200 switch (c) {
2201 default:
2202 if (any(c, "0123456789")) {
2203 c1 = my_getc(0);
2204 unget(c1);
2205 if (c1 == '<' || c1 == '>') {
2206 iounit = c - '0';
2207 goto loop;
2209 *e.linep++ = c;
2210 c = c1;
2212 break;
2214 case '#': /* Comment, skip to next newline or End-of-string */
2215 while ((c = my_getc(0)) != '\0' && c != '\n');
2216 unget(c);
2217 goto loop;
2219 case 0:
2220 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2221 return c;
2223 case '$':
2224 DBGPRINTF9(("YYLEX: found $\n"));
2225 *e.linep++ = c;
2226 c = my_getc(0);
2227 if (c == '{') {
2228 c = collect(c, '}');
2229 if (c != '\0')
2230 return c;
2231 goto pack;
2233 break;
2235 case '`':
2236 case '\'':
2237 case '"':
2238 c = collect(c, c);
2239 if (c != '\0')
2240 return c;
2241 goto pack;
2243 case '|':
2244 case '&':
2245 case ';':
2246 startl = 1;
2247 /* If more chars process them, else return NULL char */
2248 c1 = dual(c);
2249 if (c1 != '\0')
2250 return c1;
2251 return c;
2253 case '^':
2254 startl = 1;
2255 return '|';
2256 case '>':
2257 case '<':
2258 diag(c);
2259 return c;
2261 case '\n':
2262 nlseen++;
2263 gethere();
2264 startl = 1;
2265 if (multiline || cf & CONTIN) {
2266 if (interactive && e.iop <= iostack) {
2267 #if ENABLE_FEATURE_EDITING
2268 current_prompt = cprompt->value;
2269 #else
2270 prs(cprompt->value);
2271 #endif
2273 if (cf & CONTIN)
2274 goto loop;
2276 return c;
2278 case '(':
2279 case ')':
2280 startl = 1;
2281 return c;
2284 unget(c);
2286 pack:
2287 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
2288 if (e.linep >= elinep)
2289 err("word too long");
2290 else
2291 *e.linep++ = c;
2294 unget(c);
2296 if (any(c, "\"'`$"))
2297 goto loop;
2299 *e.linep++ = '\0';
2301 if (atstart) {
2302 c = rlookup(line);
2303 if (c != 0) {
2304 startl = 1;
2305 return c;
2309 yylval.cp = strsave(line, areanum);
2310 return WORD;
2314 static int collect(int c, int c1)
2316 char s[2];
2318 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2320 *e.linep++ = c;
2321 while ((c = my_getc(c1)) != c1) {
2322 if (c == 0) {
2323 unget(c);
2324 s[0] = c1;
2325 s[1] = 0;
2326 prs("no closing ");
2327 yyerror(s);
2328 return YYERRCODE;
2330 if (interactive && c == '\n' && e.iop <= iostack) {
2331 #if ENABLE_FEATURE_EDITING
2332 current_prompt = cprompt->value;
2333 #else
2334 prs(cprompt->value);
2335 #endif
2337 *e.linep++ = c;
2340 *e.linep++ = c;
2342 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2344 return 0;
2347 /* "multiline commands" helper func */
2348 /* see if next 2 chars form a shell multiline */
2349 static int dual(int c)
2351 char s[3];
2352 char *cp = s;
2354 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2356 *cp++ = c; /* c is the given "peek" char */
2357 *cp++ = my_getc(0); /* get next char of input */
2358 *cp = '\0'; /* add EOS marker */
2360 c = rlookup(s); /* see if 2 chars form a shell multiline */
2361 if (c == 0)
2362 unget(*--cp); /* String is not a shell multiline, put peek char back */
2364 return c; /* String is multiline, return numeric multiline (restab) code */
2367 static void diag(int ec)
2369 int c;
2371 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2373 c = my_getc(0);
2374 if (c == '>' || c == '<') {
2375 if (c != ec)
2376 zzerr();
2377 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
2378 c = my_getc(0);
2379 } else
2380 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
2381 if (c != '&' || yylval.i == IOHERE)
2382 unget(c);
2383 else
2384 yylval.i |= IODUP;
2387 static char *tree(unsigned size)
2389 char *t;
2391 t = getcell(size);
2392 if (t == NULL) {
2393 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2394 prs("command line too complicated\n");
2395 fail();
2396 /* NOTREACHED */
2398 return t;
2402 /* VARARGS1 */
2403 /* ARGSUSED */
2405 /* -------- exec.c -------- */
2407 static struct op **find1case(struct op *t, const char *w)
2409 struct op *t1;
2410 struct op **tp;
2411 char **wp;
2412 char *cp;
2414 if (t == NULL) {
2415 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2416 return NULL;
2419 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2420 T_CMD_NAMES[t->type]));
2422 if (t->type == TLIST) {
2423 tp = find1case(t->left, w);
2424 if (tp != NULL) {
2425 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2426 return tp;
2428 t1 = t->right; /* TPAT */
2429 } else
2430 t1 = t;
2432 for (wp = t1->words; *wp;) {
2433 cp = evalstr(*wp++, DOSUB);
2434 if (cp && gmatch(w, cp)) {
2435 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2436 &t1->left));
2437 return &t1->left;
2441 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2442 return NULL;
2445 static struct op *findcase(struct op *t, const char *w)
2447 struct op **tp;
2449 tp = find1case(t, w);
2450 return tp != NULL ? *tp : NULL;
2454 * execute tree
2457 static int execute(struct op *t, int *pin, int *pout, int act)
2459 struct op *t1;
2460 volatile int i, rv, a;
2461 const char *cp;
2462 char **wp, **wp2;
2463 struct var *vp;
2464 struct op *outtree_save;
2465 struct brkcon bc;
2467 #if __GNUC__
2468 /* Avoid longjmp clobbering */
2469 (void) &wp;
2470 #endif
2472 if (t == NULL) {
2473 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2474 return 0;
2477 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
2478 t->type, T_CMD_NAMES[t->type],
2479 ((t->words == NULL) ? "NULL" : t->words[0])));
2481 rv = 0;
2482 a = areanum++;
2483 wp = (wp2 = t->words) != NULL
2484 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2485 : NULL;
2487 switch (t->type) {
2488 case TDOT:
2489 DBGPRINTF3(("EXECUTE: TDOT\n"));
2491 outtree_save = outtree;
2493 newfile(evalstr(t->words[0], DOALL));
2495 t->left = dowholefile(TLIST, 0);
2496 t->right = NULL;
2498 outtree = outtree_save;
2500 if (t->left)
2501 rv = execute(t->left, pin, pout, 0);
2502 if (t->right)
2503 rv = execute(t->right, pin, pout, 0);
2504 break;
2506 case TPAREN:
2507 rv = execute(t->left, pin, pout, 0);
2508 break;
2510 case TCOM:
2511 rv = forkexec(t, pin, pout, act, wp);
2512 break;
2514 case TPIPE:
2516 int pv[2];
2518 rv = openpipe(pv);
2519 if (rv < 0)
2520 break;
2521 pv[0] = remap(pv[0]);
2522 pv[1] = remap(pv[1]);
2523 (void) execute(t->left, pin, pv, 0);
2524 rv = execute(t->right, pv, pout, 0);
2526 break;
2528 case TLIST:
2529 (void) execute(t->left, pin, pout, 0);
2530 rv = execute(t->right, pin, pout, 0);
2531 break;
2533 case TASYNC:
2535 int hinteractive = interactive;
2537 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2539 i = vfork();
2540 if (i == 0) { /* child */
2541 signal(SIGINT, SIG_IGN);
2542 signal(SIGQUIT, SIG_IGN);
2543 if (interactive)
2544 signal(SIGTERM, SIG_DFL);
2545 interactive = 0;
2546 if (pin == NULL) {
2547 close(0);
2548 xopen(bb_dev_null, O_RDONLY);
2550 _exit(execute(t->left, pin, pout, FEXEC));
2552 interactive = hinteractive;
2553 if (i != -1) {
2554 setval(lookup("!"), putn(i));
2555 if (pin != NULL)
2556 closepipe(pin);
2557 if (interactive) {
2558 prs(putn(i));
2559 prs("\n");
2561 } else
2562 rv = -1;
2563 setstatus(rv);
2565 break;
2567 case TOR:
2568 case TAND:
2569 rv = execute(t->left, pin, pout, 0);
2570 t1 = t->right;
2571 if (t1 != NULL && (rv == 0) == (t->type == TAND))
2572 rv = execute(t1, pin, pout, 0);
2573 break;
2575 case TFOR:
2576 if (wp == NULL) {
2577 wp = dolv + 1;
2578 i = dolc;
2579 if (i < 0)
2580 i = 0;
2581 } else {
2582 i = -1;
2583 while (*wp++ != NULL);
2585 vp = lookup(t->str);
2586 while (setjmp(bc.brkpt))
2587 if (isbreak)
2588 goto broken;
2589 brkset(&bc);
2590 for (t1 = t->left; i-- && *wp != NULL;) {
2591 setval(vp, *wp++);
2592 rv = execute(t1, pin, pout, 0);
2594 brklist = brklist->nextlev;
2595 break;
2597 case TWHILE:
2598 case TUNTIL:
2599 while (setjmp(bc.brkpt))
2600 if (isbreak)
2601 goto broken;
2602 brkset(&bc);
2603 t1 = t->left;
2604 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2605 rv = execute(t->right, pin, pout, 0);
2606 brklist = brklist->nextlev;
2607 break;
2609 case TIF:
2610 case TELIF:
2611 if (t->right != NULL) {
2612 rv = !execute(t->left, pin, pout, 0) ?
2613 execute(t->right->left, pin, pout, 0) :
2614 execute(t->right->right, pin, pout, 0);
2616 break;
2618 case TCASE:
2619 cp = evalstr(t->str, DOSUB | DOTRIM);
2620 if (cp == NULL)
2621 cp = "";
2623 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2624 ((t->str == NULL) ? "NULL" : t->str),
2625 ((cp == NULL) ? "NULL" : cp)));
2627 t1 = findcase(t->left, cp);
2628 if (t1 != NULL) {
2629 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2630 rv = execute(t1, pin, pout, 0);
2631 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2633 break;
2635 case TBRACE:
2637 iopp = t->ioact;
2638 if (i)
2639 while (*iopp)
2640 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2641 rv = -1;
2642 break;
2645 if (rv >= 0) {
2646 t1 = t->left;
2647 if (t1) {
2648 rv = execute(t1, pin, pout, 0);
2651 break;
2655 broken:
2656 t->words = wp2;
2657 isbreak = 0;
2658 freehere(areanum);
2659 freearea(areanum);
2660 areanum = a;
2661 if (interactive && intr) {
2662 closeall();
2663 fail();
2666 i = trapset;
2667 if (i != 0) {
2668 trapset = 0;
2669 runtrap(i);
2672 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2673 return rv;
2676 typedef int (*builtin_func_ptr)(struct op *);
2678 static builtin_func_ptr inbuilt(const char *s)
2680 const struct builtincmd *bp;
2682 for (bp = builtincmds; bp->name; bp++)
2683 if (strcmp(bp->name, s) == 0)
2684 return bp->builtinfunc;
2685 return NULL;
2688 static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
2690 pid_t newpid;
2691 int i, rv;
2692 builtin_func_ptr shcom = NULL;
2693 int f;
2694 const char *cp = NULL;
2695 struct ioword **iopp;
2696 int resetsig;
2697 char **owp;
2698 int forked = 0;
2700 int *hpin = pin;
2701 int *hpout = pout;
2702 char *hwp;
2703 int hinteractive;
2704 int hintr;
2705 struct brkcon *hbrklist;
2706 int hexecflg;
2708 #if __GNUC__
2709 /* Avoid longjmp clobbering */
2710 (void) &pin;
2711 (void) &pout;
2712 (void) &wp;
2713 (void) &shcom;
2714 (void) &cp;
2715 (void) &resetsig;
2716 (void) &owp;
2717 #endif
2719 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
2720 pout, act));
2721 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2722 ((t->words == NULL) ? "NULL" : t->words[0])));
2724 owp = wp;
2725 resetsig = 0;
2726 rv = -1; /* system-detected error */
2727 if (t->type == TCOM) {
2728 while (*wp++ != NULL)
2729 continue;
2730 cp = *wp;
2732 /* strip all initial assignments */
2733 /* not correct wrt PATH=yyy command etc */
2734 if (FLAG['x']) {
2735 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2736 cp, wp, owp));
2737 echo(cp ? wp : owp);
2740 if (cp == NULL && t->ioact == NULL) {
2741 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2742 continue;
2743 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
2744 return setstatus(0);
2746 if (cp != NULL) {
2747 shcom = inbuilt(cp);
2751 t->words = wp;
2752 f = act;
2754 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
2755 f & FEXEC, owp));
2757 if (shcom == NULL && (f & FEXEC) == 0) {
2758 /* Save values in case the child process alters them */
2759 hpin = pin;
2760 hpout = pout;
2761 hwp = *wp;
2762 hinteractive = interactive;
2763 hintr = intr;
2764 hbrklist = brklist;
2765 hexecflg = execflg;
2767 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2769 newpid = vfork();
2771 if (newpid == -1) {
2772 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
2773 return -1;
2776 if (newpid > 0) { /* Parent */
2777 /* Restore values */
2778 pin = hpin;
2779 pout = hpout;
2780 *wp = hwp;
2781 interactive = hinteractive;
2782 intr = hintr;
2783 brklist = hbrklist;
2784 execflg = hexecflg;
2785 /* moved up
2786 if (i == -1)
2787 return rv;
2789 if (pin != NULL)
2790 closepipe(pin);
2792 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2795 /* Must be the child process, pid should be 0 */
2796 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
2798 if (interactive) {
2799 signal(SIGINT, SIG_IGN);
2800 signal(SIGQUIT, SIG_IGN);
2801 resetsig = 1;
2803 interactive = 0;
2804 intr = 0;
2805 forked = 1;
2806 brklist = 0;
2807 execflg = 0;
2810 if (owp != NULL)
2811 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2812 if (shcom == NULL)
2813 export(lookup(cp));
2815 #ifdef COMPIPE
2816 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2817 err("piping to/from shell builtins not yet done");
2818 if (forked)
2819 _exit(-1);
2820 return -1;
2822 #endif
2824 if (pin != NULL) {
2825 xmove_fd(pin[0], 0);
2826 if (pin[1] != 0) close(pin[1]);
2828 if (pout != NULL) {
2829 xmove_fd(pout[1], 1);
2830 if (pout[1] != 1) close(pout[0]);
2833 iopp = t->ioact;
2834 if (iopp != NULL) {
2835 if (shcom != NULL && shcom != doexec) {
2836 prs(cp);
2837 err(": cannot redirect shell command");
2838 if (forked)
2839 _exit(-1);
2840 return -1;
2842 while (*iopp)
2843 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2844 if (forked)
2845 _exit(rv);
2846 return rv;
2850 if (shcom) {
2851 i = setstatus((*shcom) (t));
2852 if (forked)
2853 _exit(i);
2854 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2855 return i;
2858 /* should use FIOCEXCL */
2859 for (i = FDBASE; i < NOFILE; i++)
2860 close(i);
2861 if (resetsig) {
2862 signal(SIGINT, SIG_DFL);
2863 signal(SIGQUIT, SIG_DFL);
2866 if (t->type == TPAREN)
2867 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2868 if (wp[0] == NULL)
2869 _exit(0);
2871 cp = rexecve(wp[0], wp, makenv(0, NULL));
2872 prs(wp[0]);
2873 prs(": ");
2874 err(cp);
2875 if (!execflg)
2876 trap[0] = NULL;
2878 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2880 leave();
2881 /* NOTREACHED */
2882 _exit(1);
2886 * 0< 1> are ignored as required
2887 * within pipelines.
2889 static int iosetup(struct ioword *iop, int pipein, int pipeout)
2891 int u = -1;
2892 char *cp = NULL;
2893 const char *msg;
2895 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2896 pipein, pipeout));
2898 if (iop->io_unit == IODEFAULT) /* take default */
2899 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2901 if (pipein && iop->io_unit == 0)
2902 return 0;
2904 if (pipeout && iop->io_unit == 1)
2905 return 0;
2907 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2908 if ((iop->io_flag & IOHERE) == 0) {
2909 cp = iop->io_name; /* huh?? */
2910 cp = evalstr(cp, DOSUB | DOTRIM);
2911 if (cp == NULL)
2912 return 1;
2915 if (iop->io_flag & IODUP) {
2916 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2917 prs(cp);
2918 err(": illegal >& argument");
2919 return 1;
2921 if (*cp == '-')
2922 iop->io_flag = IOCLOSE;
2923 iop->io_flag &= ~(IOREAD | IOWRITE);
2925 switch (iop->io_flag) {
2926 case IOREAD:
2927 u = open(cp, O_RDONLY);
2928 break;
2930 case IOHERE:
2931 case IOHERE | IOXHERE:
2932 u = herein(iop->io_name, iop->io_flag & IOXHERE);
2933 cp = (char*)"here file";
2934 break;
2936 case IOWRITE | IOCAT:
2937 u = open(cp, O_WRONLY);
2938 if (u >= 0) {
2939 lseek(u, (long) 0, SEEK_END);
2940 break;
2942 case IOWRITE:
2943 u = creat(cp, 0666);
2944 break;
2946 case IODUP:
2947 u = dup2(*cp - '0', iop->io_unit);
2948 break;
2950 case IOCLOSE:
2951 close(iop->io_unit);
2952 return 0;
2954 if (u < 0) {
2955 prs(cp);
2956 prs(": cannot ");
2957 warn(msg);
2958 return 1;
2960 if (u != iop->io_unit) {
2961 dup2(u, iop->io_unit);
2962 close(u);
2964 return 0;
2968 * Enter a new loop level (marked for break/continue).
2970 static void brkset(struct brkcon *bc)
2972 bc->nextlev = brklist;
2973 brklist = bc;
2977 * Wait for the last process created.
2978 * Print a message for each process found
2979 * that was killed by a signal.
2980 * Ignore interrupt signals while waiting
2981 * unless `canintr' is true.
2983 static int waitfor(int lastpid, int canintr)
2985 int pid, rv;
2986 int s;
2987 int oheedint = heedint;
2989 heedint = 0;
2990 rv = 0;
2991 do {
2992 pid = wait(&s);
2993 if (pid == -1) {
2994 if (errno != EINTR || canintr)
2995 break;
2996 } else {
2997 rv = WAITSIG(s);
2998 if (rv != 0) {
2999 if (rv < ARRAY_SIZE(signame)) {
3000 if (signame[rv] != NULL) {
3001 if (pid != lastpid) {
3002 prn(pid);
3003 prs(": ");
3005 prs(signame[rv]);
3007 } else {
3008 if (pid != lastpid) {
3009 prn(pid);
3010 prs(": ");
3012 prs("Signal ");
3013 prn(rv);
3014 prs(" ");
3016 if (WAITCORE(s))
3017 prs(" - core dumped");
3018 if (rv >= ARRAY_SIZE(signame) || signame[rv])
3019 prs("\n");
3020 rv = -1;
3021 } else
3022 rv = WAITVAL(s);
3024 } while (pid != lastpid);
3025 heedint = oheedint;
3026 if (intr) {
3027 if (interactive) {
3028 if (canintr)
3029 intr = 0;
3030 } else {
3031 if (exstat == 0)
3032 exstat = rv;
3033 onintr(0);
3036 return rv;
3039 static int setstatus(int s)
3041 exstat = s;
3042 setval(lookup("?"), putn(s));
3043 return s;
3047 * PATH-searching interface to execve.
3048 * If getenv("PATH") were kept up-to-date,
3049 * execvp might be used.
3051 static const char *rexecve(char *c, char **v, char **envp)
3053 int i;
3054 const char *sp;
3055 char *tp;
3056 int eacces = 0, asis = 0;
3057 char *name = c;
3059 if (ENABLE_FEATURE_SH_STANDALONE) {
3060 if (find_applet_by_name(name)) {
3061 /* We have to exec here since we vforked. Running
3062 * run_applet_and_exit() won't work and bad things
3063 * will happen. */
3064 execve(bb_busybox_exec_path, v, envp);
3068 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3070 sp = any('/', c) ? "" : path->value;
3071 asis = (*sp == '\0');
3072 while (asis || *sp != '\0') {
3073 asis = 0;
3074 tp = e.linep;
3075 for (; *sp != '\0'; tp++) {
3076 *tp = *sp++;
3077 if (*tp == ':') {
3078 asis = (*sp == '\0');
3079 break;
3082 if (tp != e.linep)
3083 *tp++ = '/';
3084 for (i = 0; (*tp++ = c[i++]) != '\0';);
3086 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3088 execve(e.linep, v, envp);
3090 switch (errno) {
3091 case ENOEXEC:
3092 *v = e.linep;
3093 tp = *--v;
3094 *v = e.linep;
3095 execve(DEFAULT_SHELL, v, envp);
3096 *v = tp;
3097 return "no Shell";
3099 case ENOMEM:
3100 return (char *) bb_msg_memory_exhausted;
3102 case E2BIG:
3103 return "argument list too long";
3105 case EACCES:
3106 eacces++;
3107 break;
3110 return errno == ENOENT ? "not found" : "cannot execute";
3114 * Run the command produced by generator `f'
3115 * applied to stream `arg'.
3117 static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3119 struct op *otree;
3120 struct wdblock *swdlist;
3121 struct wdblock *siolist;
3122 jmp_buf ev, rt;
3123 xint *ofail;
3124 int rv;
3126 #if __GNUC__
3127 /* Avoid longjmp clobbering */
3128 (void) &rv;
3129 #endif
3131 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3132 areanum, outtree, failpt));
3134 areanum++;
3135 swdlist = wdlist;
3136 siolist = iolist;
3137 otree = outtree;
3138 ofail = failpt;
3139 rv = -1;
3141 errpt = ev;
3142 if (newenv(setjmp(errpt)) == 0) {
3143 wdlist = 0;
3144 iolist = 0;
3145 pushio(argp, f);
3146 e.iobase = e.iop;
3147 yynerrs = 0;
3148 failpt = rt;
3149 if (setjmp(failpt) == 0 && yyparse() == 0)
3150 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3151 quitenv();
3152 } else {
3153 DBGPRINTF(("RUN: error from newenv()!\n"));
3156 wdlist = swdlist;
3157 iolist = siolist;
3158 failpt = ofail;
3159 outtree = otree;
3160 freearea(areanum--);
3162 return rv;
3165 /* -------- do.c -------- */
3168 * built-in commands: doX
3171 static int dohelp(struct op *t)
3173 int col;
3174 const struct builtincmd *x;
3176 puts("\nBuilt-in commands:\n"
3177 "-------------------");
3179 col = 0;
3180 x = builtincmds;
3181 while (x->name) {
3182 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
3183 if (col > 60) {
3184 bb_putchar('\n');
3185 col = 0;
3187 x++;
3189 #if ENABLE_FEATURE_SH_STANDALONE
3191 const struct bb_applet *applet = applets;
3193 while (applet->name) {
3194 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
3195 if (col > 60) {
3196 bb_putchar('\n');
3197 col = 0;
3199 applet++;
3202 #endif
3203 puts("\n");
3204 return EXIT_SUCCESS;
3207 static int dolabel(struct op *t)
3209 return 0;
3212 static int dochdir(struct op *t)
3214 const char *cp, *er;
3216 cp = t->words[1];
3217 if (cp == NULL) {
3218 cp = homedir->value;
3219 if (cp != NULL)
3220 goto do_cd;
3221 er = ": no home directory";
3222 } else {
3223 do_cd:
3224 if (chdir(cp) >= 0)
3225 return 0;
3226 er = ": bad directory";
3228 prs(cp != NULL ? cp : "cd");
3229 err(er);
3230 return 1;
3233 static int doshift(struct op *t)
3235 int n;
3237 n = t->words[1] ? getn(t->words[1]) : 1;
3238 if (dolc < n) {
3239 err("nothing to shift");
3240 return 1;
3242 dolv[n] = dolv[0];
3243 dolv += n;
3244 dolc -= n;
3245 setval(lookup("#"), putn(dolc));
3246 return 0;
3250 * execute login and newgrp directly
3252 static int dologin(struct op *t)
3254 const char *cp;
3256 if (interactive) {
3257 signal(SIGINT, SIG_DFL);
3258 signal(SIGQUIT, SIG_DFL);
3260 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3261 prs(t->words[0]);
3262 prs(": ");
3263 err(cp);
3264 return 1;
3267 static int doumask(struct op *t)
3269 int i, n;
3270 char *cp;
3272 cp = t->words[1];
3273 if (cp == NULL) {
3274 i = umask(0);
3275 umask(i);
3276 for (n = 3 * 4; (n -= 3) >= 0;)
3277 fputc('0' + ((i >> n) & 07), stderr);
3278 fputc('\n', stderr);
3279 } else {
3280 /* huh??? '8','9' are not allowed! */
3281 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3282 n = n * 8 + (*cp - '0');
3283 umask(n);
3285 return 0;
3288 static int doexec(struct op *t)
3290 int i;
3291 jmp_buf ex;
3292 xint *ofail;
3294 t->ioact = NULL;
3295 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
3296 if (i == 0)
3297 return 1;
3298 execflg = 1;
3299 ofail = failpt;
3300 failpt = ex;
3301 if (setjmp(failpt) == 0)
3302 execute(t, NOPIPE, NOPIPE, FEXEC);
3303 failpt = ofail;
3304 execflg = 0;
3305 return 1;
3308 static int dodot(struct op *t)
3310 int i;
3311 const char *sp;
3312 char *tp;
3313 char *cp;
3314 int maltmp;
3316 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
3318 cp = t->words[1];
3319 if (cp == NULL) {
3320 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3321 return 0;
3323 DBGPRINTF(("DODOT: cp is %s\n", cp));
3325 sp = any('/', cp) ? ":" : path->value;
3327 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3328 ((sp == NULL) ? "NULL" : sp),
3329 ((e.linep == NULL) ? "NULL" : e.linep)));
3331 while (*sp) {
3332 tp = e.linep;
3333 while (*sp && (*tp = *sp++) != ':')
3334 tp++;
3335 if (tp != e.linep)
3336 *tp++ = '/';
3338 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3340 /* Original code */
3341 i = open(e.linep, O_RDONLY);
3342 if (i >= 0) {
3343 exstat = 0;
3344 maltmp = remap(i);
3345 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3347 next(maltmp); /* Basically a PUSHIO */
3349 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3351 return exstat;
3353 } /* while */
3355 prs(cp);
3356 err(": not found");
3358 return -1;
3361 static int dowait(struct op *t)
3363 int i;
3364 char *cp;
3366 cp = t->words[1];
3367 if (cp != NULL) {
3368 i = getn(cp);
3369 if (i == 0)
3370 return 0;
3371 } else
3372 i = -1;
3373 setstatus(waitfor(i, 1));
3374 return 0;
3377 static int doread(struct op *t)
3379 char *cp, **wp;
3380 int nb = 0;
3381 int nl = 0;
3383 if (t->words[1] == NULL) {
3384 err("Usage: read name ...");
3385 return 1;
3387 for (wp = t->words + 1; *wp; wp++) {
3388 for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
3389 nb = read(0, cp, sizeof(*cp));
3390 if (nb != sizeof(*cp))
3391 break;
3392 nl = (*cp == '\n');
3393 if (nl || (wp[1] && any(*cp, ifs->value)))
3394 break;
3396 *cp = '\0';
3397 if (nb <= 0)
3398 break;
3399 setval(lookup(*wp), e.linep);
3401 return nb <= 0;
3404 static int doeval(struct op *t)
3406 return RUN(awordlist, t->words + 1, wdchar);
3409 static int dotrap(struct op *t)
3411 int n, i;
3412 int resetsig;
3414 if (t->words[1] == NULL) {
3415 for (i = 0; i <= _NSIG; i++)
3416 if (trap[i]) {
3417 prn(i);
3418 prs(": ");
3419 prs(trap[i]);
3420 prs("\n");
3422 return 0;
3424 resetsig = isdigit(*t->words[1]);
3425 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3426 n = getsig(t->words[i]);
3427 freecell(trap[n]);
3428 trap[n] = 0;
3429 if (!resetsig) {
3430 if (*t->words[1] != '\0') {
3431 trap[n] = strsave(t->words[1], 0);
3432 setsig(n, sig);
3433 } else
3434 setsig(n, SIG_IGN);
3435 } else {
3436 if (interactive) {
3437 if (n == SIGINT)
3438 setsig(n, onintr);
3439 else
3440 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3441 } else
3442 setsig(n, SIG_DFL);
3445 return 0;
3448 static int getsig(char *s)
3450 int n;
3452 n = getn(s);
3453 if (n < 0 || n > _NSIG) {
3454 err("trap: bad signal number");
3455 n = 0;
3457 return n;
3460 static void setsig(int n, sighandler_t f)
3462 if (n == 0)
3463 return;
3464 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3465 ourtrap[n] = 1;
3466 signal(n, f);
3470 static int getn(char *as)
3472 char *s;
3473 int n, m;
3475 s = as;
3476 m = 1;
3477 if (*s == '-') {
3478 m = -1;
3479 s++;
3481 for (n = 0; isdigit(*s); s++)
3482 n = (n * 10) + (*s - '0');
3483 if (*s) {
3484 prs(as);
3485 err(": bad number");
3487 return n * m;
3490 static int dobreak(struct op *t)
3492 return brkcontin(t->words[1], 1);
3495 static int docontinue(struct op *t)
3497 return brkcontin(t->words[1], 0);
3500 static int brkcontin(char *cp, int val)
3502 struct brkcon *bc;
3503 int nl;
3505 nl = cp == NULL ? 1 : getn(cp);
3506 if (nl <= 0)
3507 nl = 999;
3508 do {
3509 bc = brklist;
3510 if (bc == NULL)
3511 break;
3512 brklist = bc->nextlev;
3513 } while (--nl);
3514 if (nl) {
3515 err("bad break/continue level");
3516 return 1;
3518 isbreak = val;
3519 longjmp(bc->brkpt, 1);
3520 /* NOTREACHED */
3523 static int doexit(struct op *t)
3525 char *cp;
3527 execflg = 0;
3528 cp = t->words[1];
3529 if (cp != NULL)
3530 setstatus(getn(cp));
3532 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3534 leave();
3535 /* NOTREACHED */
3536 return 0;
3539 static int doexport(struct op *t)
3541 rdexp(t->words + 1, export, EXPORT);
3542 return 0;
3545 static int doreadonly(struct op *t)
3547 rdexp(t->words + 1, ronly, RONLY);
3548 return 0;
3551 static void rdexp(char **wp, void (*f) (struct var *), int key)
3553 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3554 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3556 if (*wp != NULL) {
3557 for (; *wp != NULL; wp++) {
3558 if (isassign(*wp)) {
3559 char *cp;
3561 assign(*wp, COPYV);
3562 for (cp = *wp; *cp != '='; cp++);
3563 *cp = '\0';
3565 if (checkname(*wp))
3566 (*f) (lookup(*wp));
3567 else
3568 badid(*wp);
3570 } else
3571 putvlist(key, 1);
3574 static void badid(char *s)
3576 prs(s);
3577 err(": bad identifier");
3580 static int doset(struct op *t)
3582 struct var *vp;
3583 char *cp;
3584 int n;
3586 cp = t->words[1];
3587 if (cp == NULL) {
3588 for (vp = vlist; vp; vp = vp->next)
3589 varput(vp->name, 1);
3590 return 0;
3592 if (*cp == '-') {
3593 /* bad: t->words++; */
3594 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3595 if (*++cp == 0)
3596 FLAG['x'] = FLAG['v'] = 0;
3597 else {
3598 for (; *cp; cp++) {
3599 switch (*cp) {
3600 case 'e':
3601 if (!interactive)
3602 FLAG['e']++;
3603 break;
3605 default:
3606 if (*cp >= 'a' && *cp <= 'z')
3607 FLAG[(int) *cp]++;
3608 break;
3612 setdash();
3614 if (t->words[1]) {
3615 t->words[0] = dolv[0];
3616 for (n = 1; t->words[n]; n++)
3617 setarea((char *) t->words[n], 0);
3618 dolc = n - 1;
3619 dolv = t->words;
3620 setval(lookup("#"), putn(dolc));
3621 setarea((char *) (dolv - 1), 0);
3623 return 0;
3626 static void varput(char *s, int out)
3628 if (isalnum(*s) || *s == '_') {
3629 write(out, s, strlen(s));
3630 write(out, "\n", 1);
3636 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3637 * This file contains code for the times builtin.
3639 static int dotimes(struct op *t)
3641 struct tms buf;
3642 long clk_tck = sysconf(_SC_CLK_TCK);
3644 times(&buf);
3645 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3646 (int) (buf.tms_utime / clk_tck / 60),
3647 ((double) buf.tms_utime) / clk_tck,
3648 (int) (buf.tms_stime / clk_tck / 60),
3649 ((double) buf.tms_stime) / clk_tck,
3650 (int) (buf.tms_cutime / clk_tck / 60),
3651 ((double) buf.tms_cutime) / clk_tck,
3652 (int) (buf.tms_cstime / clk_tck / 60),
3653 ((double) buf.tms_cstime) / clk_tck);
3654 return 0;
3658 /* -------- eval.c -------- */
3661 * ${}
3662 * `command`
3663 * blank interpretation
3664 * quoting
3665 * glob
3668 static char **eval(char **ap, int f)
3670 struct wdblock *wb;
3671 char **wp;
3672 char **wf;
3673 jmp_buf ev;
3675 #if __GNUC__
3676 /* Avoid longjmp clobbering */
3677 (void) &wp;
3678 (void) &ap;
3679 #endif
3681 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3683 wp = NULL;
3684 wb = NULL;
3685 wf = NULL;
3686 errpt = ev;
3687 if (newenv(setjmp(errpt)) == 0) {
3688 while (*ap && isassign(*ap))
3689 expand(*ap++, &wb, f & ~DOGLOB);
3690 if (FLAG['k']) {
3691 for (wf = ap; *wf; wf++) {
3692 if (isassign(*wf))
3693 expand(*wf, &wb, f & ~DOGLOB);
3696 for (wb = addword((char *) 0, wb); *ap; ap++) {
3697 if (!FLAG['k'] || !isassign(*ap))
3698 expand(*ap, &wb, f & ~DOKEY);
3700 wb = addword((char *) 0, wb);
3701 wp = getwords(wb);
3702 quitenv();
3703 } else
3704 gflg = 1;
3706 return gflg ? (char **) NULL : wp;
3711 * Make the exported environment from the exported
3712 * names in the dictionary. Keyword assignments
3713 * will already have been done.
3715 static char **makenv(int all, struct wdblock *wb)
3717 struct var *vp;
3719 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3721 for (vp = vlist; vp; vp = vp->next)
3722 if (all || vp->status & EXPORT)
3723 wb = addword(vp->name, wb);
3724 wb = addword((char *) 0, wb);
3725 return getwords(wb);
3728 static int expand(const char *cp, struct wdblock **wbp, int f)
3730 jmp_buf ev;
3731 char *xp;
3733 #if __GNUC__
3734 /* Avoid longjmp clobbering */
3735 (void) &cp;
3736 #endif
3738 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3740 gflg = 0;
3742 if (cp == NULL)
3743 return 0;
3745 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3746 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3748 xp = strsave(cp, areanum);
3749 if (f & DOTRIM)
3750 unquote(xp);
3751 *wbp = addword(xp, *wbp);
3752 return 1;
3754 errpt = ev;
3755 if (newenv(setjmp(errpt)) == 0) {
3756 PUSHIO(aword, cp, strchar);
3757 e.iobase = e.iop;
3758 while ((xp = blank(f)) && gflg == 0) {
3759 e.linep = xp;
3760 xp = strsave(xp, areanum);
3761 if ((f & DOGLOB) == 0) {
3762 if (f & DOTRIM)
3763 unquote(xp);
3764 *wbp = addword(xp, *wbp);
3765 } else
3766 *wbp = glob(xp, *wbp);
3768 quitenv();
3769 } else
3770 gflg = 1;
3771 return gflg == 0;
3774 static char *evalstr(char *cp, int f)
3776 struct wdblock *wb;
3778 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3780 wb = NULL;
3781 if (expand(cp, &wb, f)) {
3782 if (wb == NULL || wb->w_nword == 0
3783 || (cp = wb->w_words[0]) == NULL
3785 // TODO: I suspect that
3786 // char *evalstr(char *cp, int f) is actually
3787 // const char *evalstr(const char *cp, int f)!
3788 cp = (char*)"";
3790 DELETE(wb);
3791 } else
3792 cp = NULL;
3793 return cp;
3798 * Blank interpretation and quoting
3800 static char *blank(int f)
3802 int c, c1;
3803 char *sp;
3804 int scanequals, foundequals;
3806 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3808 sp = e.linep;
3809 scanequals = f & DOKEY;
3810 foundequals = 0;
3812 loop:
3813 c = subgetc('"', foundequals);
3814 switch (c) {
3815 case 0:
3816 if (sp == e.linep)
3817 return 0;
3818 *e.linep++ = 0;
3819 return sp;
3821 default:
3822 if (f & DOBLANK && any(c, ifs->value))
3823 goto loop;
3824 break;
3826 case '"':
3827 case '\'':
3828 scanequals = 0;
3829 if (INSUB())
3830 break;
3831 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3832 if (c == 0)
3833 break;
3834 if (c == '\'' || !any(c, "$`\""))
3835 c |= QUOTE;
3836 *e.linep++ = c;
3838 c = 0;
3840 unget(c);
3841 if (!isalpha(c) && c != '_')
3842 scanequals = 0;
3843 for (;;) {
3844 c = subgetc('"', foundequals);
3845 if (c == 0 ||
3846 f & (DOBLANK && any(c, ifs->value)) ||
3847 (!INSUB() && any(c, "\"'"))) {
3848 scanequals = 0;
3849 unget(c);
3850 if (any(c, "\"'"))
3851 goto loop;
3852 break;
3854 if (scanequals) {
3855 if (c == '=') {
3856 foundequals = 1;
3857 scanequals = 0;
3858 } else if (!isalnum(c) && c != '_')
3859 scanequals = 0;
3861 *e.linep++ = c;
3863 *e.linep++ = 0;
3864 return sp;
3868 * Get characters, substituting for ` and $
3870 static int subgetc(char ec, int quoted)
3872 char c;
3874 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3876 again:
3877 c = my_getc(ec);
3878 if (!INSUB() && ec != '\'') {
3879 if (c == '`') {
3880 if (grave(quoted) == 0)
3881 return 0;
3882 e.iop->task = XGRAVE;
3883 goto again;
3885 if (c == '$') {
3886 c = dollar(quoted);
3887 if (c == 0) {
3888 e.iop->task = XDOLL;
3889 goto again;
3893 return c;
3897 * Prepare to generate the string returned by ${} substitution.
3899 static int dollar(int quoted)
3901 int otask;
3902 struct io *oiop;
3903 char *dolp;
3904 char *s, c, *cp = NULL;
3905 struct var *vp;
3907 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3909 c = readc();
3910 s = e.linep;
3911 if (c != '{') {
3912 *e.linep++ = c;
3913 if (isalpha(c) || c == '_') {
3914 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3915 if (e.linep < elinep)
3916 *e.linep++ = c;
3917 unget(c);
3919 c = 0;
3920 } else {
3921 oiop = e.iop;
3922 otask = e.iop->task;
3924 e.iop->task = XOTHER;
3925 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3926 if (e.linep < elinep)
3927 *e.linep++ = c;
3928 if (oiop == e.iop)
3929 e.iop->task = otask;
3930 if (c != '}') {
3931 err("unclosed ${");
3932 gflg++;
3933 return c;
3936 if (e.linep >= elinep) {
3937 err("string in ${} too long");
3938 gflg++;
3939 e.linep -= 10;
3941 *e.linep = 0;
3942 if (*s)
3943 for (cp = s + 1; *cp; cp++)
3944 if (any(*cp, "=-+?")) {
3945 c = *cp;
3946 *cp++ = 0;
3947 break;
3949 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3950 if (dolc > 1) {
3951 /* currently this does not distinguish $* and $@ */
3952 /* should check dollar */
3953 e.linep = s;
3954 PUSHIO(awordlist, dolv + 1, dolchar);
3955 return 0;
3956 } else { /* trap the nasty ${=} */
3957 s[0] = '1';
3958 s[1] = '\0';
3961 vp = lookup(s);
3962 dolp = vp->value;
3963 if (dolp == null) {
3964 switch (c) {
3965 case '=':
3966 if (isdigit(*s)) {
3967 err("cannot use ${...=...} with $n");
3968 gflg++;
3969 break;
3971 setval(vp, cp);
3972 dolp = vp->value;
3973 break;
3975 case '-':
3976 dolp = strsave(cp, areanum);
3977 break;
3979 case '?':
3980 if (*cp == 0) {
3981 prs("missing value for ");
3982 err(s);
3983 } else
3984 err(cp);
3985 gflg++;
3986 break;
3988 } else if (c == '+')
3989 dolp = strsave(cp, areanum);
3990 if (FLAG['u'] && dolp == null) {
3991 prs("unset variable: ");
3992 err(s);
3993 gflg++;
3995 e.linep = s;
3996 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
3997 return 0;
4001 * Run the command in `...` and read its output.
4004 static int grave(int quoted)
4006 /* moved to G: static char child_cmd[LINELIM]; */
4008 const char *cp;
4009 int i;
4010 int j;
4011 int pf[2];
4012 const char *src;
4013 char *dest;
4014 int count;
4015 int ignore;
4016 int ignore_once;
4017 char *argument_list[4];
4018 struct wdblock *wb = NULL;
4020 #if __GNUC__
4021 /* Avoid longjmp clobbering */
4022 (void) &cp;
4023 #endif
4025 for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
4026 if (*cp == 0) {
4027 err("no closing `");
4028 return 0;
4032 /* string copy with dollar expansion */
4033 src = e.iop->argp->aword;
4034 dest = child_cmd;
4035 count = 0;
4036 ignore = 0;
4037 ignore_once = 0;
4038 while ((*src != '`') && (count < LINELIM)) {
4039 if (*src == '\'')
4040 ignore = !ignore;
4041 if (*src == '\\')
4042 ignore_once = 1;
4043 if (*src == '$' && !ignore && !ignore_once) {
4044 struct var *vp;
4045 char var_name[LINELIM];
4046 char alt_value[LINELIM];
4047 int var_index = 0;
4048 int alt_index = 0;
4049 char operator = 0;
4050 int braces = 0;
4051 char *value;
4053 src++;
4054 if (*src == '{') {
4055 braces = 1;
4056 src++;
4059 var_name[var_index++] = *src++;
4060 while (isalnum(*src) || *src=='_')
4061 var_name[var_index++] = *src++;
4062 var_name[var_index] = 0;
4064 if (braces) {
4065 switch (*src) {
4066 case '}':
4067 break;
4068 case '-':
4069 case '=':
4070 case '+':
4071 case '?':
4072 operator = * src;
4073 break;
4074 default:
4075 err("unclosed ${\n");
4076 return 0;
4078 if (operator) {
4079 src++;
4080 while (*src && (*src != '}')) {
4081 alt_value[alt_index++] = *src++;
4083 alt_value[alt_index] = 0;
4084 if (*src != '}') {
4085 err("unclosed ${\n");
4086 return 0;
4089 src++;
4092 if (isalpha(*var_name)) {
4093 /* let subshell handle it instead */
4095 char *namep = var_name;
4097 *dest++ = '$';
4098 if (braces)
4099 *dest++ = '{';
4100 while (*namep)
4101 *dest++ = *namep++;
4102 if (operator) {
4103 char *altp = alt_value;
4104 *dest++ = operator;
4105 while (*altp)
4106 *dest++ = *altp++;
4108 if (braces)
4109 *dest++ = '}';
4111 wb = addword(lookup(var_name)->name, wb);
4112 } else {
4113 /* expand */
4115 vp = lookup(var_name);
4116 if (vp->value != null)
4117 value = (operator == '+') ?
4118 alt_value : vp->value;
4119 else if (operator == '?') {
4120 err(alt_value);
4121 return 0;
4122 } else if (alt_index && (operator != '+')) {
4123 value = alt_value;
4124 if (operator == '=')
4125 setval(vp, value);
4126 } else
4127 continue;
4129 while (*value && (count < LINELIM)) {
4130 *dest++ = *value++;
4131 count++;
4134 } else {
4135 *dest++ = *src++;
4136 count++;
4137 ignore_once = 0;
4140 *dest = '\0';
4142 if (openpipe(pf) < 0)
4143 return 0;
4145 while ((i = vfork()) == -1 && errno == EAGAIN);
4147 DBGPRINTF3(("GRAVE: i is %p\n", io));
4149 if (i < 0) {
4150 closepipe(pf);
4151 err((char *) bb_msg_memory_exhausted);
4152 return 0;
4154 if (i != 0) {
4155 waitpid(i, NULL, 0);
4156 e.iop->argp->aword = ++cp;
4157 close(pf[1]);
4158 PUSHIO(afile, remap(pf[0]),
4159 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
4160 return 1;
4162 /* allow trapped signals */
4163 /* XXX - Maybe this signal stuff should go as well? */
4164 for (j = 0; j <= _NSIG; j++)
4165 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4166 signal(j, SIG_DFL);
4168 /* Testcase where below checks are needed:
4169 * close stdout & run this script:
4170 * files=`ls`
4171 * echo "$files" >zz
4173 xmove_fd(pf[1], 1);
4174 if (pf[0] != 1) close(pf[0]);
4176 argument_list[0] = (char *) DEFAULT_SHELL;
4177 argument_list[1] = (char *) "-c";
4178 argument_list[2] = child_cmd;
4179 argument_list[3] = NULL;
4181 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4182 prs(argument_list[0]);
4183 prs(": ");
4184 err(cp);
4185 _exit(1);
4189 static char *unquote(char *as)
4191 char *s;
4193 s = as;
4194 if (s != NULL)
4195 while (*s)
4196 *s++ &= ~QUOTE;
4197 return as;
4200 /* -------- glob.c -------- */
4203 * glob
4206 #define scopy(x) strsave((x), areanum)
4207 #define BLKSIZ 512
4208 #define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4210 static struct wdblock *cl, *nl;
4211 static const char spcl[] ALIGN1= "[?*";
4213 static struct wdblock *glob(char *cp, struct wdblock *wb)
4215 int i;
4216 char *pp;
4218 if (cp == 0)
4219 return wb;
4220 i = 0;
4221 for (pp = cp; *pp; pp++)
4222 if (any(*pp, spcl))
4223 i++;
4224 else if (!any(*pp & ~QUOTE, spcl))
4225 *pp &= ~QUOTE;
4226 if (i != 0) {
4227 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
4228 nl = newword(cl->w_nword * 2);
4229 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
4230 for (pp = cl->w_words[i]; *pp; pp++)
4231 if (any(*pp, spcl)) {
4232 globname(cl->w_words[i], pp);
4233 break;
4235 if (*pp == '\0')
4236 nl = addword(scopy(cl->w_words[i]), nl);
4238 for (i = 0; i < cl->w_nword; i++)
4239 DELETE(cl->w_words[i]);
4240 DELETE(cl);
4242 for (i = 0; i < cl->w_nword; i++)
4243 unquote(cl->w_words[i]);
4244 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4245 if (cl->w_nword) {
4246 for (i = 0; i < cl->w_nword; i++)
4247 wb = addword(cl->w_words[i], wb);
4248 DELETE(cl);
4249 return wb;
4252 wb = addword(unquote(cp), wb);
4253 return wb;
4256 static void globname(char *we, char *pp)
4258 char *np, *cp;
4259 char *name, *gp, *dp;
4260 int k;
4261 DIR *dirp;
4262 struct dirent *de;
4263 char dname[NAME_MAX + 1];
4264 struct stat dbuf;
4266 for (np = we; np != pp; pp--)
4267 if (pp[-1] == '/')
4268 break;
4269 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4270 *cp++ = *np++;
4271 *cp++ = '.';
4272 *cp = '\0';
4273 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4274 *cp++ = *np++;
4275 *cp = '\0';
4276 dirp = opendir(dp);
4277 if (dirp == 0) {
4278 DELETE(dp);
4279 DELETE(gp);
4280 return;
4282 dname[NAME_MAX] = '\0';
4283 while ((de = readdir(dirp)) != NULL) {
4284 /* XXX Hmmm... What this could be? (abial) */
4286 if (ent[j].d_ino == 0)
4287 continue;
4289 strncpy(dname, de->d_name, NAME_MAX);
4290 if (dname[0] == '.')
4291 if (*gp != '.')
4292 continue;
4293 for (k = 0; k < NAME_MAX; k++)
4294 if (any(dname[k], spcl))
4295 dname[k] |= QUOTE;
4296 if (gmatch(dname, gp)) {
4297 name = generate(we, pp, dname, np);
4298 if (*np && !anys(np, spcl)) {
4299 if (stat(name, &dbuf)) {
4300 DELETE(name);
4301 continue;
4304 nl = addword(name, nl);
4307 closedir(dirp);
4308 DELETE(dp);
4309 DELETE(gp);
4313 * generate a pathname as below.
4314 * start..end1 / middle end
4315 * the slashes come for free
4317 static char *generate(char *start1, char *end1, char *middle, char *end)
4319 char *p;
4320 char *op, *xp;
4322 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4323 for (xp = start1; xp != end1;)
4324 *op++ = *xp++;
4325 for (xp = middle; (*op++ = *xp++) != '\0';);
4326 op--;
4327 for (xp = end; (*op++ = *xp++) != '\0';);
4328 return p;
4331 static int anyspcl(struct wdblock *wb)
4333 int i;
4334 char **wd;
4336 wd = wb->w_words;
4337 for (i = 0; i < wb->w_nword; i++)
4338 if (anys(spcl, *wd++))
4339 return 1;
4340 return 0;
4343 static int xstrcmp(char *p1, char *p2)
4345 return strcmp(*(char **) p1, *(char **) p2);
4349 /* -------- word.c -------- */
4351 static struct wdblock *newword(int nw)
4353 struct wdblock *wb;
4355 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4356 wb->w_bsize = nw;
4357 wb->w_nword = 0;
4358 return wb;
4361 static struct wdblock *addword(char *wd, struct wdblock *wb)
4363 struct wdblock *wb2;
4364 int nw;
4366 if (wb == NULL)
4367 wb = newword(NSTART);
4368 nw = wb->w_nword;
4369 if (nw >= wb->w_bsize) {
4370 wb2 = newword(nw * 2);
4371 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4372 nw * sizeof(char *));
4373 wb2->w_nword = nw;
4374 DELETE(wb);
4375 wb = wb2;
4377 wb->w_words[wb->w_nword++] = wd;
4378 return wb;
4381 static char **getwords(struct wdblock *wb)
4383 char **wd;
4384 int nb;
4386 if (wb == NULL)
4387 return NULL;
4388 if (wb->w_nword == 0) {
4389 DELETE(wb);
4390 return NULL;
4392 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4393 memcpy((char *) wd, (char *) wb->w_words, nb);
4394 DELETE(wb); /* perhaps should done by caller */
4395 return wd;
4398 static int (*func) (char *, char *);
4399 static int globv;
4401 static void glob3(char *i, char *j, char *k)
4403 char *index1, *index2, *index3;
4404 int c;
4405 int m;
4407 m = globv;
4408 index1 = i;
4409 index2 = j;
4410 index3 = k;
4411 do {
4412 c = *index1;
4413 *index1++ = *index3;
4414 *index3++ = *index2;
4415 *index2++ = c;
4416 } while (--m);
4419 static void glob2(char *i, char *j)
4421 char *index1, *index2, c;
4422 int m;
4424 m = globv;
4425 index1 = i;
4426 index2 = j;
4427 do {
4428 c = *index1;
4429 *index1++ = *index2;
4430 *index2++ = c;
4431 } while (--m);
4434 static void glob1(char *base, char *lim)
4436 char *i, *j;
4437 int v2;
4438 char *lptr, *hptr;
4439 int c;
4440 unsigned n;
4442 v2 = globv;
4444 top:
4445 n = (int) (lim - base);
4446 if (n <= v2)
4447 return;
4448 n = v2 * (n / (2 * v2));
4449 hptr = lptr = base + n;
4450 i = base;
4451 j = lim - v2;
4452 for (;;) {
4453 if (i < lptr) {
4454 c = (*func) (i, lptr);
4455 if (c == 0) {
4456 lptr -= v2;
4457 glob2(i, lptr);
4458 continue;
4460 if (c < 0) {
4461 i += v2;
4462 continue;
4466 begin:
4467 if (j > hptr) {
4468 c = (*func) (hptr, j);
4469 if (c == 0) {
4470 hptr += v2;
4471 glob2(hptr, j);
4472 goto begin;
4474 if (c > 0) {
4475 if (i == lptr) {
4476 hptr += v2;
4477 glob3(i, hptr, j);
4478 i = (lptr += v2);
4479 goto begin;
4481 glob2(i, j);
4482 j -= v2;
4483 i += v2;
4484 continue;
4486 j -= v2;
4487 goto begin;
4491 if (i == lptr) {
4492 if (lptr - base >= lim - hptr) {
4493 glob1(hptr + v2, lim);
4494 lim = lptr;
4495 } else {
4496 glob1(base, lptr);
4497 base = hptr + v2;
4499 goto top;
4502 lptr -= v2;
4503 glob3(j, lptr, i);
4504 j = (hptr -= v2);
4508 static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
4510 func = a3;
4511 globv = a2;
4512 glob1(a0, a0 + a1 * a2);
4516 /* -------- io.c -------- */
4519 * shell IO
4522 static int my_getc(int ec)
4524 int c;
4526 if (e.linep > elinep) {
4527 while ((c = readc()) != '\n' && c);
4528 err("input line too long");
4529 gflg++;
4530 return c;
4532 c = readc();
4533 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
4534 if (c == '\\') {
4535 c = readc();
4536 if (c == '\n' && ec != '\"')
4537 return my_getc(ec);
4538 c |= QUOTE;
4541 return c;
4544 static void unget(int c)
4546 if (e.iop >= e.iobase)
4547 e.iop->peekc = c;
4550 static int eofc(void)
4552 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4555 static int readc(void)
4557 int c;
4559 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
4561 for (; e.iop >= e.iobase; e.iop--) {
4562 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
4563 c = e.iop->peekc;
4564 if (c != '\0') {
4565 e.iop->peekc = 0;
4566 return c;
4568 if (e.iop->prev != 0) {
4569 c = (*e.iop->iofn)(e.iop->argp, e.iop);
4570 if (c != '\0') {
4571 if (c == -1) {
4572 e.iop++;
4573 continue;
4575 if (e.iop == iostack)
4576 ioecho(c);
4577 e.iop->prev = c;
4578 return e.iop->prev;
4580 if (e.iop->task == XIO && e.iop->prev != '\n') {
4581 e.iop->prev = 0;
4582 if (e.iop == iostack)
4583 ioecho('\n');
4584 return '\n';
4587 if (e.iop->task == XIO) {
4588 if (multiline) {
4589 e.iop->prev = 0;
4590 return e.iop->prev;
4592 if (interactive && e.iop == iostack + 1) {
4593 #if ENABLE_FEATURE_EDITING
4594 current_prompt = prompt->value;
4595 #else
4596 prs(prompt->value);
4597 #endif
4600 } /* FOR */
4602 if (e.iop >= iostack) {
4603 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
4604 return 0;
4607 DBGPRINTF(("READC: leave()...\n"));
4608 leave();
4610 /* NOTREACHED */
4611 return 0;
4614 static void ioecho(char c)
4616 if (FLAG['v'])
4617 write(2, &c, sizeof c);
4621 static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4623 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
4624 argp->afid, e.iop));
4626 /* Set env ptr for io source to next array spot and check for array overflow */
4627 if (++e.iop >= &iostack[NPUSH]) {
4628 e.iop--;
4629 err("Shell input nested too deeply");
4630 gflg++;
4631 return;
4634 /* We did not overflow the NPUSH array spots so setup data structs */
4636 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
4638 if (argp->afid != AFID_NOBUF)
4639 e.iop->argp = argp;
4640 else {
4642 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4643 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4645 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4647 if (e.iop == &iostack[0])
4648 e.iop->argp->afbuf = &mainbuf;
4649 else
4650 e.iop->argp->afbuf = &sharedbuf;
4652 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4653 /* This line appears to be active when running scripts from command line */
4654 if ((isatty(e.iop->argp->afile) == 0)
4655 && (e.iop == &iostack[0]
4656 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4657 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4658 bufid = AFID_ID; /* AFID_ID = 0 */
4660 e.iop->argp->afid = bufid; /* assign buffer id */
4663 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
4664 iostack, e.iop, e.iop->argp->afbuf));
4665 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
4666 &mainbuf, &sharedbuf, bufid, e.iop));
4670 e.iop->prev = ~'\n';
4671 e.iop->peekc = 0;
4672 e.iop->xchar = 0;
4673 e.iop->nlcount = 0;
4675 if (fn == filechar || fn == linechar)
4676 e.iop->task = XIO;
4677 else if (fn == (int (*)(struct ioarg *)) gravechar
4678 || fn == (int (*)(struct ioarg *)) qgravechar)
4679 e.iop->task = XGRAVE;
4680 else
4681 e.iop->task = XOTHER;
4684 static struct io *setbase(struct io *ip)
4686 struct io *xp;
4688 xp = e.iobase;
4689 e.iobase = ip;
4690 return xp;
4694 * Input generating functions
4698 * Produce the characters of a string, then a newline, then EOF.
4700 static int nlchar(struct ioarg *ap)
4702 int c;
4704 if (ap->aword == NULL)
4705 return 0;
4706 c = *ap->aword++;
4707 if (c == 0) {
4708 ap->aword = NULL;
4709 return '\n';
4711 return c;
4715 * Given a list of words, produce the characters
4716 * in them, with a space after each word.
4718 static int wdchar(struct ioarg *ap)
4720 char c;
4721 char **wl;
4723 wl = ap->awordlist;
4724 if (wl == NULL)
4725 return 0;
4726 if (*wl != NULL) {
4727 c = *(*wl)++;
4728 if (c != 0)
4729 return c & 0177;
4730 ap->awordlist++;
4731 return ' ';
4733 ap->awordlist = NULL;
4734 return '\n';
4738 * Return the characters of a list of words,
4739 * producing a space between them.
4741 static int dolchar(struct ioarg *ap)
4743 char *wp;
4745 wp = *ap->awordlist++;
4746 if (wp != NULL) {
4747 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4748 return -1;
4750 return 0;
4753 static int xxchar(struct ioarg *ap)
4755 int c;
4757 if (ap->aword == NULL)
4758 return 0;
4759 c = *ap->aword++;
4760 if (c == '\0') {
4761 ap->aword = NULL;
4762 return ' ';
4764 return c;
4768 * Produce the characters from a single word (string).
4770 static int strchar(struct ioarg *ap)
4772 if (ap->aword == NULL)
4773 return 0;
4774 return *ap->aword++;
4778 * Produce quoted characters from a single word (string).
4780 static int qstrchar(struct ioarg *ap)
4782 int c;
4784 if (ap->aword == NULL)
4785 return 0;
4786 c = *ap->aword++;
4787 if (c)
4788 c |= QUOTE;
4789 return c;
4793 * Return the characters from a file.
4795 static int filechar(struct ioarg *ap)
4797 int i;
4798 char c;
4799 struct iobuf *bp = ap->afbuf;
4801 if (ap->afid != AFID_NOBUF) {
4802 i = (ap->afid != bp->id);
4803 if (i || bp->bufp == bp->ebufp) {
4804 if (i)
4805 lseek(ap->afile, ap->afpos, SEEK_SET);
4807 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4808 if (i <= 0) {
4809 closef(ap->afile);
4810 return 0;
4813 bp->id = ap->afid;
4814 bp->bufp = bp->buf;
4815 bp->ebufp = bp->bufp + i;
4818 ap->afpos++;
4819 return *bp->bufp++ & 0177;
4821 #if ENABLE_FEATURE_EDITING
4822 if (interactive && isatty(ap->afile)) {
4823 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
4824 static int position = 0, size = 0;
4826 while (size == 0 || position >= size) {
4827 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4828 size = strlen(filechar_cmdbuf);
4829 position = 0;
4831 c = filechar_cmdbuf[position];
4832 position++;
4833 return c;
4835 #endif
4836 i = safe_read(ap->afile, &c, sizeof(c));
4837 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4841 * Return the characters from a here temp file.
4843 static int herechar(struct ioarg *ap)
4845 char c;
4847 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4848 close(ap->afile);
4849 c = '\0';
4851 return c;
4855 * Return the characters produced by a process (`...`).
4856 * Quote them if required, and remove any trailing newline characters.
4858 static int gravechar(struct ioarg *ap, struct io *iop)
4860 int c;
4862 c = qgravechar(ap, iop) & ~QUOTE;
4863 if (c == '\n')
4864 c = ' ';
4865 return c;
4868 static int qgravechar(struct ioarg *ap, struct io *iop)
4870 int c;
4872 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4874 if (iop->xchar) {
4875 if (iop->nlcount) {
4876 iop->nlcount--;
4877 return '\n' | QUOTE;
4879 c = iop->xchar;
4880 iop->xchar = 0;
4881 } else if ((c = filechar(ap)) == '\n') {
4882 iop->nlcount = 1;
4883 while ((c = filechar(ap)) == '\n')
4884 iop->nlcount++;
4885 iop->xchar = c;
4886 if (c == 0)
4887 return c;
4888 iop->nlcount--;
4889 c = '\n';
4891 return c != 0 ? c | QUOTE : 0;
4895 * Return a single command (usually the first line) from a file.
4897 static int linechar(struct ioarg *ap)
4899 int c;
4901 c = filechar(ap);
4902 if (c == '\n') {
4903 if (!multiline) {
4904 closef(ap->afile);
4905 ap->afile = -1; /* illegal value */
4908 return c;
4912 * remap fd into Shell's fd space
4914 static int remap(int fd)
4916 int i;
4917 int map[NOFILE];
4918 int newfd;
4920 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
4922 if (fd < e.iofd) {
4923 for (i = 0; i < NOFILE; i++)
4924 map[i] = 0;
4926 do {
4927 map[fd] = 1;
4928 newfd = dup(fd);
4929 fd = newfd;
4930 } while (fd >= 0 && fd < e.iofd);
4932 for (i = 0; i < NOFILE; i++)
4933 if (map[i])
4934 close(i);
4936 if (fd < 0)
4937 err("too many files open in shell");
4940 return fd;
4943 static int openpipe(int *pv)
4945 int i;
4947 i = pipe(pv);
4948 if (i < 0)
4949 err("can't create pipe - try again");
4950 return i;
4953 static void closepipe(int *pv)
4955 if (pv != NULL) {
4956 close(*pv++);
4957 close(*pv);
4962 /* -------- here.c -------- */
4965 * here documents
4968 static void markhere(char *s, struct ioword *iop)
4970 struct here *h, *lh;
4972 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
4974 h = (struct here *) space(sizeof(struct here));
4975 if (h == NULL)
4976 return;
4978 h->h_tag = evalstr(s, DOSUB);
4979 if (h->h_tag == 0)
4980 return;
4982 h->h_iop = iop;
4983 iop->io_name = 0;
4984 h->h_next = NULL;
4985 if (inhere == 0)
4986 inhere = h;
4987 else {
4988 for (lh = inhere; lh != NULL; lh = lh->h_next) {
4989 if (lh->h_next == 0) {
4990 lh->h_next = h;
4991 break;
4995 iop->io_flag |= IOHERE | IOXHERE;
4996 for (s = h->h_tag; *s; s++) {
4997 if (*s & QUOTE) {
4998 iop->io_flag &= ~IOXHERE;
4999 *s &= ~QUOTE;
5002 h->h_dosub = iop->io_flag & IOXHERE;
5005 static void gethere(void)
5007 struct here *h, *hp;
5009 DBGPRINTF7(("GETHERE: enter...\n"));
5011 /* Scan here files first leaving inhere list in place */
5012 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5013 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
5015 /* Make inhere list active - keep list intact for scraphere */
5016 if (hp != NULL) {
5017 hp->h_next = acthere;
5018 acthere = inhere;
5019 inhere = NULL;
5023 static void readhere(char **name, char *s, int ec)
5025 int tf;
5026 char tname[30] = ".msh_XXXXXX";
5027 int c;
5028 jmp_buf ev;
5029 char myline[LINELIM + 1];
5030 char *thenext;
5032 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
5034 tf = mkstemp(tname);
5035 if (tf < 0)
5036 return;
5038 *name = strsave(tname, areanum);
5039 errpt = ev;
5040 if (newenv(setjmp(errpt)) != 0)
5041 unlink(tname);
5042 else {
5043 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
5044 e.iobase = e.iop;
5045 for (;;) {
5046 if (interactive && e.iop <= iostack) {
5047 #if ENABLE_FEATURE_EDITING
5048 current_prompt = cprompt->value;
5049 #else
5050 prs(cprompt->value);
5051 #endif
5053 thenext = myline;
5054 while ((c = my_getc(ec)) != '\n' && c) {
5055 if (ec == '\'')
5056 c &= ~QUOTE;
5057 if (thenext >= &myline[LINELIM]) {
5058 c = 0;
5059 break;
5061 *thenext++ = c;
5063 *thenext = 0;
5064 if (strcmp(s, myline) == 0 || c == 0)
5065 break;
5066 *thenext++ = '\n';
5067 write(tf, myline, (int) (thenext - myline));
5069 if (c == 0) {
5070 prs("here document `");
5071 prs(s);
5072 err("' unclosed");
5074 quitenv();
5076 close(tf);
5080 * open here temp file.
5081 * if unquoted here, expand here temp file into second temp file.
5083 static int herein(char *hname, int xdoll)
5085 int hf;
5086 int tf;
5088 #if __GNUC__
5089 /* Avoid longjmp clobbering */
5090 (void) &tf;
5091 #endif
5092 if (hname == NULL)
5093 return -1;
5095 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5097 hf = open(hname, O_RDONLY);
5098 if (hf < 0)
5099 return -1;
5101 if (xdoll) {
5102 char c;
5103 char tname[30] = ".msh_XXXXXX";
5104 jmp_buf ev;
5106 tf = mkstemp(tname);
5107 if (tf < 0)
5108 return -1;
5109 errpt = ev;
5110 if (newenv(setjmp(errpt)) == 0) {
5111 PUSHIO(afile, hf, herechar);
5112 setbase(e.iop);
5113 while ((c = subgetc(0, 0)) != 0) {
5114 c &= ~QUOTE;
5115 write(tf, &c, sizeof c);
5117 quitenv();
5118 } else
5119 unlink(tname);
5120 close(tf);
5121 tf = open(tname, O_RDONLY);
5122 unlink(tname);
5123 return tf;
5125 return hf;
5128 static void scraphere(void)
5130 struct here *h;
5132 DBGPRINTF7(("SCRAPHERE: enter...\n"));
5134 for (h = inhere; h != NULL; h = h->h_next) {
5135 if (h->h_iop && h->h_iop->io_name)
5136 unlink(h->h_iop->io_name);
5138 inhere = NULL;
5141 /* unlink here temp files before a freearea(area) */
5142 static void freehere(int area)
5144 struct here *h, *hl;
5146 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5148 hl = NULL;
5149 for (h = acthere; h != NULL; h = h->h_next)
5150 if (getarea((char *) h) >= area) {
5151 if (h->h_iop->io_name != NULL)
5152 unlink(h->h_iop->io_name);
5153 if (hl == NULL)
5154 acthere = h->h_next;
5155 else
5156 hl->h_next = h->h_next;
5157 } else
5158 hl = h;
5162 /* -------- sh.c -------- */
5164 * shell
5167 int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
5168 int msh_main(int argc, char **argv)
5170 int f;
5171 char *s;
5172 int cflag;
5173 char *name, **ap;
5174 int (*iof) (struct ioarg *);
5176 PTR_TO_GLOBALS = xzalloc(sizeof(G));
5177 sharedbuf.id = AFID_NOBUF;
5178 mainbuf.id = AFID_NOBUF;
5179 e.linep = line;
5180 elinep = line + sizeof(line) - 5;
5182 #if ENABLE_FEATURE_EDITING
5183 line_input_state = new_line_input_t(FOR_SHELL);
5184 #endif
5186 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5188 initarea();
5189 ap = environ;
5190 if (ap != NULL) {
5191 while (*ap)
5192 assign(*ap++, !COPYV);
5193 for (ap = environ; *ap;)
5194 export(lookup(*ap++));
5196 closeall();
5197 areanum = 1;
5199 shell = lookup("SHELL");
5200 if (shell->value == null)
5201 setval(shell, (char *)DEFAULT_SHELL);
5202 export(shell);
5204 homedir = lookup("HOME");
5205 if (homedir->value == null)
5206 setval(homedir, "/");
5207 export(homedir);
5209 setval(lookup("$"), putn(getpid()));
5211 path = lookup("PATH");
5212 if (path->value == null) {
5213 /* Can be merged with same string elsewhere in bbox */
5214 if (geteuid() == 0)
5215 setval(path, bb_default_root_path);
5216 else
5217 setval(path, bb_default_path);
5219 export(path);
5221 ifs = lookup("IFS");
5222 if (ifs->value == null)
5223 setval(ifs, " \t\n");
5225 #ifdef MSHDEBUG
5226 mshdbg_var = lookup("MSHDEBUG");
5227 if (mshdbg_var->value == null)
5228 setval(mshdbg_var, "0");
5229 #endif
5231 prompt = lookup("PS1");
5232 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5233 if (prompt->value == null)
5234 #endif
5235 setval(prompt, DEFAULT_USER_PROMPT);
5236 if (geteuid() == 0) {
5237 setval(prompt, DEFAULT_ROOT_PROMPT);
5238 prompt->status &= ~EXPORT;
5240 cprompt = lookup("PS2");
5241 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5242 if (cprompt->value == null)
5243 #endif
5244 setval(cprompt, "> ");
5246 iof = filechar;
5247 cflag = 0;
5248 name = *argv++;
5249 if (--argc >= 1) {
5250 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5251 for (s = argv[0] + 1; *s; s++)
5252 switch (*s) {
5253 case 'c':
5254 prompt->status &= ~EXPORT;
5255 cprompt->status &= ~EXPORT;
5256 setval(prompt, "");
5257 setval(cprompt, "");
5258 cflag = 1;
5259 if (--argc > 0)
5260 PUSHIO(aword, *++argv, iof = nlchar);
5261 break;
5263 case 'q':
5264 qflag = SIG_DFL;
5265 break;
5267 case 's':
5268 /* standard input */
5269 break;
5271 case 't':
5272 prompt->status &= ~EXPORT;
5273 setval(prompt, "");
5274 iof = linechar;
5275 break;
5277 case 'i':
5278 interactive++;
5279 default:
5280 if (*s >= 'a' && *s <= 'z')
5281 FLAG[(int) *s]++;
5283 } else {
5284 argv--;
5285 argc++;
5288 if (iof == filechar && --argc > 0) {
5289 setval(prompt, "");
5290 setval(cprompt, "");
5291 prompt->status &= ~EXPORT;
5292 cprompt->status &= ~EXPORT;
5294 /* Shell is non-interactive, activate printf-based debug */
5295 #ifdef MSHDEBUG
5296 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5297 if (mshdbg < 0)
5298 mshdbg = 0;
5299 #endif
5300 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5302 name = *++argv;
5303 if (newfile(name))
5304 exit(1); /* Exit on error */
5308 setdash();
5310 /* This won't be true if PUSHIO has been called, say from newfile() above */
5311 if (e.iop < iostack) {
5312 PUSHIO(afile, 0, iof);
5313 if (isatty(0) && isatty(1) && !cflag) {
5314 interactive++;
5315 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
5316 #ifdef MSHDEBUG
5317 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
5318 #else
5319 printf("\n\n%s built-in shell (msh)\n", bb_banner);
5320 #endif
5321 printf("Enter 'help' for a list of built-in commands.\n\n");
5322 #endif
5326 signal(SIGQUIT, qflag);
5327 if (name && name[0] == '-') {
5328 interactive++;
5329 f = open(".profile", O_RDONLY);
5330 if (f >= 0)
5331 next(remap(f));
5332 f = open("/etc/profile", O_RDONLY);
5333 if (f >= 0)
5334 next(remap(f));
5336 if (interactive)
5337 signal(SIGTERM, sig);
5339 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5340 signal(SIGINT, onintr);
5341 dolv = argv;
5342 dolc = argc;
5343 dolv[0] = name;
5344 if (dolc > 1) {
5345 for (ap = ++argv; --argc > 0;) {
5346 *ap = *argv++;
5347 if (assign(*ap, !COPYV)) {
5348 dolc--; /* keyword */
5349 } else {
5350 ap++;
5354 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5356 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
5358 for (;;) {
5359 if (interactive && e.iop <= iostack) {
5360 #if ENABLE_FEATURE_EDITING
5361 current_prompt = prompt->value;
5362 #else
5363 prs(prompt->value);
5364 #endif
5366 onecommand();
5367 /* Ensure that getenv("PATH") stays current */
5368 setenv("PATH", path->value, 1);
5371 DBGPRINTF(("MSH_MAIN: returning.\n"));
5376 * Copyright (c) 1987,1997, Prentice Hall
5377 * All rights reserved.
5379 * Redistribution and use of the MINIX operating system in source and
5380 * binary forms, with or without modification, are permitted provided
5381 * that the following conditions are met:
5383 * Redistributions of source code must retain the above copyright
5384 * notice, this list of conditions and the following disclaimer.
5386 * Redistributions in binary form must reproduce the above
5387 * copyright notice, this list of conditions and the following
5388 * disclaimer in the documentation and/or other materials provided
5389 * with the distribution.
5391 * Neither the name of Prentice Hall nor the names of the software
5392 * authors or contributors may be used to endorse or promote
5393 * products derived from this software without specific prior
5394 * written permission.
5396 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5397 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5398 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5399 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5400 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5401 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5402 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5403 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5404 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5405 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5406 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5407 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.