1 /* vi: set sw=4 ts=4: */
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>
23 # include <sys/types.h>
24 # include <sys/stat.h>
25 # include <sys/wait.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
)
52 static char *utoa_to_buf(unsigned n
, char *buf
, unsigned buflen
)
55 assert(sizeof(unsigned) == 4);
58 for (i
= 1000000000; i
; i
/= 10) {
60 if (res
|| out
|| i
== 1) {
70 static char *itoa_to_buf(int n
, char *buf
, unsigned buflen
)
72 if (buflen
&& n
< 0) {
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';
87 extern char **environ
;
90 /*#define MSHDEBUG 1*/
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
109 #define RCPRINTF(x) if (mshdbg_rc) printf 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$ "
134 # define DEFAULT_ROOT_PROMPT "# "
135 # define DEFAULT_USER_PROMPT "$ "
139 /* -------- sh.h -------- */
145 #define NPUSH 8 /* limit to input nesting */
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 */
167 #define NOBLOCK ((struct op *)NULL)
168 #define NOWORD ((char *)NULL)
169 #define NOWORDS ((char **)NULL)
170 #define NOPIPE ((int *)NULL)
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.
197 int type
; /* operation type, see below */
198 char **words
; /* arguments to a command */
199 struct ioword
**ioact
; /* IO actions (eg, < > >>) */
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 /* && */
218 #define TPAT 14 /* pattern in case */
219 #define TBRACE 15 /* {c-list} */
220 #define TASYNC 16 /* c & */
221 /* Added to support "." file expansion */
224 /* Strings for names to make debug easier */
226 static const char *const T_CMD_NAMES
[] = {
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)
269 struct brkcon
*nextlev
;
276 * -k: look for name=value everywhere on command line
278 * -t: exit after reading and executing one command
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
;
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)
331 /* #define SHRINKBY (64) */
335 #define ALIGN (sizeof(int)-1)
344 /* -------- grammar stuff -------- */
369 /* Added for "." file expansion */
372 #define YYERRCODE 300
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 -------- */
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)
429 /* -------- io.h -------- */
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 */
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 */
450 int (*iofn
) (struct ioarg
*, struct io
*);
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
);
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 */
521 /* bounds are arbitrary */
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
);
576 struct ioword
*h_iop
;
580 static const char *const signame
[] = {
583 NULL
, /* interrupt */
585 "Illegal instruction",
589 "Floating Point Exception",
594 NULL
, /* broken pipe */
604 static const struct res restab
[] = {
629 int (*builtinfunc
)(struct op
*t
);
631 static const struct builtincmd builtincmds
[] = {
634 { "break" , dobreak
},
636 { "continue", docontinue
},
640 { "export" , doexport
},
642 { "login" , dologin
},
643 { "newgrp" , dologin
},
645 { "readonly", doreadonly
},
647 { "shift" , doshift
},
648 { "times" , dotimes
},
650 { "umask" , doumask
},
655 static struct op
*scantree(struct op
*);
656 static struct op
*dowholefile(int, int);
664 static int interactive
; /* Is this an interactive shell */
666 static int multiline
; /* \n changed to ; */
667 static struct op
*outtree
; /* result from parser */
670 static struct brkcon
*brklist
;
672 static struct wdblock
*wdlist
;
673 static struct wdblock
*iolist
;
676 static struct var
*mshdbg_var
;
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 */
689 static char *null
= (char*)""; /* null value for variable */
690 static int heedint
= 1; /* heed interrupt signals */
691 static void (*qflag
)(int) = SIG_IGN
;
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 */
705 static void *brkaddr
;
708 * parsing & execution environment
714 xint
*errpt
; /* void * */
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 */
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
];
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 )
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
));
758 DBGPRINTF(("T: W1: %s", t
->words
[0]));
762 void print_tree(struct op
*head
)
765 DBGPRINTF(("PRINT_TREE: no tree\n"));
769 DBGPRINTF(("NODE: %p, left %p, right %p\n", head
, head
->left
,
773 print_tree(head
->left
);
776 print_tree(head
->right
);
778 #endif /* MSHDEBUG */
784 static void prs(const char *s
)
787 write(2, s
, strlen(s
));
790 static void prn(unsigned u
)
795 static void echo(char **wp
)
800 for (i
= 0; wp
[i
]; i
++) {
808 static void closef(int i
)
814 static void closeall(void)
818 for (u
= NUFILE
; u
< NOFILE
;)
823 /* fail but return to process next command */
824 static void fail(void) ATTRIBUTE_NORETURN
;
825 static void fail(void)
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"));
846 static void warn(const char *s
)
857 static void err(const char *s
)
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.
880 void * __q = (void *)-1; \
881 if (brkaddr + (int)(X) < brktop) { \
883 brkaddr += (int)(X); \
888 static void initarea(void)
890 brkaddr
= xmalloc(AREASIZE
);
891 brktop
= brkaddr
+ AREASIZE
;
893 while ((long) sbrk(0) & ALIGN
)
895 areabot
= (struct region
*) sbrk(REGSIZE
);
897 areabot
->next
= areabot
;
898 areabot
->area
= BUSY
;
903 static char *getcell(unsigned nbytes
)
906 struct region
*p
, *q
;
913 /* silly and defeats the algorithm */
915 * round upwards and add administration area
917 nregio
= (nbytes
+ (REGSIZE
- 1)) / REGSIZE
+ 1;
920 if (p
->area
> areanum
) {
924 while ((q
= p
->next
)->area
> areanum
&& q
!= areanxt
)
927 * exit loop if cell big enough
936 i
= nregio
>= GROWBY
? nregio
: GROWBY
;
937 p
= (struct region
*) sbrk(i
* REGSIZE
);
938 if (p
== (struct region
*) -1)
943 abort(); /* allocated areas are contiguous */
953 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
955 areanxt
= p
+ nregio
;
958 * split into requested area and rest
960 if (areanxt
+ 1 > q
) {
962 abort(); /* insufficient space left for admin */
965 areanxt
->area
= FREE
;
969 return (char *) (p
+ 1);
972 static void freecell(char *cp
)
976 p
= (struct region
*) cp
;
984 #define DELETE(obj) freecell((char *)obj)
986 static void freearea(int a
)
988 struct region
*p
, *top
;
991 for (p
= areabot
; p
!= top
; p
= p
->next
)
996 static void setarea(char *cp
, int a
)
1000 p
= (struct region
*) cp
;
1005 static int getarea(char *cp
)
1007 return ((struct region
*) cp
- 1)->area
;
1010 static void garbage(void)
1012 struct region
*p
, *q
, *top
;
1015 for (p
= areabot
; p
!= top
; p
= p
->next
) {
1016 if (p
->area
> areanum
) {
1017 while ((q
= p
->next
)->area
> areanum
)
1023 if (areatop
>= q
+ SHRINKBY
&& q
->area
> areanum
) {
1024 brk((char *) (q
+ 1));
1032 static char *space(int n
)
1038 err("out of string space");
1042 static char *strsave(const char *s
, int a
)
1046 cp
= space(strlen(s
) + 1);
1048 // FIXME: I highly doubt this is good.
1057 /* -------- var.c -------- */
1059 static int eqname(const char *n1
, const char *n2
)
1061 for (; *n1
!= '=' && *n1
!= '\0'; n1
++)
1064 return *n2
== '\0' || *n2
== '=';
1067 static const char *findeq(const char *cp
)
1069 while (*cp
!= '\0' && *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
;
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
);
1099 for (vp
= vlist
; vp
; vp
= vp
->next
)
1100 if (eqname(vp
->name
, 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*)"";
1111 while ((*xp
= *n
++) != '\0' && *xp
!= '=')
1115 setarea((char *) vp
, 0);
1116 setarea((char *) vp
->name
, 0);
1119 vp
->status
= GETCELL
;
1125 * if name is not NULL, it must be
1126 * a prefix of the space `val',
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
)
1137 if (vp
->status
& RONLY
) {
1139 while (*xp
&& *xp
!= '=')
1140 fputc(*xp
++, stderr
);
1141 err(" is read-only");
1146 xp
= space(strlen(vp
->name
) + strlen(val
) + 2);
1149 /* make string: name=value */
1153 while ((*xp
= *cp
++) != '\0' && *xp
!= '=')
1160 if (vp
->status
& GETCELL
)
1161 freecell(vp
->name
); /* form new string `name=value' */
1162 vp
->name
= (char*)name
;
1163 vp
->value
= (char*)val
;
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
)
1189 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s
));
1192 /* no isalpha() - we shouldn't use locale */
1193 /* c | 0x20 - lowercase (Latin) letters */
1194 if (c
!= '_' && (unsigned)((c
|0x20) - 'a') > 25)
1205 && (unsigned)(c
- '0') > 9 /* not number */
1206 && (unsigned)((c
|0x20) - 'a') > 25 /* not letter */
1213 static int assign(const char *s
, int cf
)
1218 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s
, cf
));
1220 if (!isalpha(*s
) && *s
!= '_')
1222 for (cp
= s
; *cp
!= '='; cp
++)
1223 if (*cp
== '\0' || (!isalnum(*cp
) && *cp
!= '_'))
1226 nameval(vp
, ++cp
, cf
== COPYV
? NULL
: s
);
1228 vp
->status
&= ~GETCELL
;
1232 static int checkname(char *cp
)
1234 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp
));
1236 if (!isalpha(*cp
++) && *(cp
- 1) != '_')
1239 if (!isalnum(*cp
++) && *(cp
- 1) != '_')
1244 static void putvlist(int f
, int out
)
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);
1264 static void sig(int i
)
1270 static void runtrap(int i
)
1275 if (trapstr
== NULL
)
1281 RUN(aword
, trapstr
, nlchar
);
1285 static void setdash(void)
1289 char m
['z' - 'a' + 1];
1292 for (c
= 'a'; c
<= 'z'; c
++)
1296 setval(lookup("-"), m
);
1299 static int newfile(char *s
)
1303 DBGPRINTF7(("NEWFILE: opening %s\n", s
));
1306 if (NOT_LONE_DASH(s
)) {
1307 DBGPRINTF(("NEWFILE: s is %s\n", s
));
1308 f
= open(s
, O_RDONLY
);
1311 err(": cannot open");
1321 struct op
*scantree(struct op
*head
)
1328 if (head
->left
!= NULL
) {
1329 dotnode
= scantree(head
->left
);
1334 if (head
->right
!= NULL
) {
1335 dotnode
= scantree(head
->right
);
1340 if (head
->words
== 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
));
1354 static void onecommand(void)
1359 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree
));
1379 setjmp(failpt
); /* Bruce Evans' fix */
1381 if (setjmp(failpt
) || yyparse() || intr
) {
1382 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1387 if (!interactive
&& intr
)
1400 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1402 execute(outtree
, NOPIPE
, NOPIPE
, 0);
1405 if (!interactive
&& intr
) {
1417 static int newenv(int f
)
1421 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f
));
1428 ep
= (struct env
*) space(sizeof(*ep
));
1441 static void quitenv(void)
1446 DBGPRINTF(("QUITENV: e.oenv=%p\n", e
.oenv
));
1452 /* should close `'d files */
1454 while (--fd
>= e
.iofd
)
1460 * Is character c in s?
1462 static int any(int c
, const char *s
)
1471 * Is any character from s1 in s2?
1473 static int anys(const char *s1
, const char *s2
)
1481 static char *putn(int 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
);
1500 } else if (heedint
) {
1507 /* -------- gmatch.c -------- */
1509 * int gmatch(string, pattern)
1510 * char *string, *pattern;
1512 * Match a pattern as in sh(1).
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
;
1532 if (p
[1] == '-' && p
[2] != ']') {
1537 if (c
== sub
|| (c
<= sub
&& sub
<= d
))
1539 } while (*++p
!= ']');
1540 return found
? p
+ 1 : NULL
;
1543 static int gmatch(const char *s
, const char *p
)
1547 if (s
== NULL
|| p
== NULL
)
1550 while ((pc
= *p
++ & CMASK
) != '\0') {
1567 if (*p
== '\0' || gmatch(s
, p
))
1569 } while (*s
++ != '\0');
1573 if (sc
!= (pc
& ~QUOTE
))
1581 /* -------- csyn.c -------- */
1583 * shell: syntax (C version)
1586 static void yyerror(const char *s
) ATTRIBUTE_NORETURN
;
1587 static void yyerror(const char *s
)
1590 if (interactive
&& e
.iop
<= iostack
) {
1592 while (eofc() == 0 && yylex(0) != '\n');
1598 static void zzerr(void) ATTRIBUTE_NORETURN
;
1599 static void zzerr(void)
1601 yyerror("syntax error");
1606 DBGPRINTF7(("YYPARSE: enter...\n"));
1613 return (yynerrs
!= 0);
1616 static struct op
*pipeline(int cf
)
1621 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf
));
1625 DBGPRINTF9(("PIPELINE: t=%p\n", t
));
1628 while ((c
= yylex(0)) == '|') {
1629 p
= command(CONTIN
);
1631 DBGPRINTF8(("PIPELINE: error!\n"));
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
);
1645 DBGPRINTF7(("PIPELINE: returning t=%p\n", t
));
1649 static struct op
*andor(void)
1654 DBGPRINTF7(("ANDOR: enter...\n"));
1658 DBGPRINTF9(("ANDOR: t=%p\n", t
));
1661 while ((c
= yylex(0)) == LOGAND
|| c
== LOGOR
) {
1662 p
= pipeline(CONTIN
);
1664 DBGPRINTF8(("ANDOR: error!\n"));
1668 t
= block(c
== LOGAND
? TAND
: TOR
, t
, p
, NOWORDS
);
1674 DBGPRINTF7(("ANDOR: returning t=%p\n", t
));
1678 static struct op
*c_list(void)
1683 DBGPRINTF7(("C_LIST: enter...\n"));
1690 t
= block(TASYNC
, t
, NOBLOCK
, NOWORDS
);
1692 while ((c
= yylex(0)) == ';' || c
== '&'
1693 || (multiline
&& c
== '\n')) {
1701 p
= block(TASYNC
, p
, NOBLOCK
, NOWORDS
);
1709 DBGPRINTF7(("C_LIST: returning t=%p\n", t
));
1713 static int synio(int cf
)
1719 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf
));
1722 if (c
!= '<' && c
!= '>') {
1729 iop
= io(iounit
, i
, yylval
.cp
);
1733 markhere(yylval
.cp
, iop
);
1735 DBGPRINTF7(("SYNIO: returning 1\n"));
1739 static void musthave(int c
, int cf
)
1741 peeksym
= yylex(cf
);
1743 DBGPRINTF7(("MUSTHAVE: error!\n"));
1750 static struct op
*simple(void)
1756 switch (peeksym
= yylex(0)) {
1777 static struct op
*nested(int type
, int mark
)
1781 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type
, mark
));
1787 return block(type
, t
, NOBLOCK
, NOWORDS
);
1790 static struct op
*command(int cf
)
1793 struct wdblock
*iosave
;
1796 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf
));
1822 t
= nested(TPAREN
, ')');
1826 t
= nested(TBRACE
, '}');
1836 t
->words
= wordlist();
1838 if (c
!= '\n' && c
!= ';')
1840 t
->left
= dogroup(0);
1848 t
->type
= c
== WHILE
? TWHILE
: TUNTIL
;
1850 t
->right
= dogroup(1);
1862 musthave(IN
, CONTIN
);
1865 t
->left
= caselist();
1876 t
->right
= thenpart();
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 */
1900 DBGPRINTF(("COMMAND: returning %p\n", t
));
1905 static struct op
*dowholefile(int type
, int mark
)
1909 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type
, mark
));
1914 t
= block(type
, t
, NOBLOCK
, NOWORDS
);
1915 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t
));
1919 static struct op
*dogroup(int onlydone
)
1925 if (c
== DONE
&& onlydone
)
1934 static struct op
*thenpart(void)
1947 if (t
->left
== NULL
)
1949 t
->right
= elsepart();
1953 static struct op
*elsepart(void)
1958 switch (c
= yylex(0)) {
1969 t
->right
= thenpart();
1978 static struct op
*caselist(void)
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
));
1992 static struct op
*casepart(void)
1996 DBGPRINTF7(("CASEPART: enter...\n"));
2000 t
->words
= pattern();
2003 peeksym
= yylex(CONTIN
);
2004 if (peeksym
!= ESAC
)
2005 musthave(BREAK
, CONTIN
);
2007 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t
));
2012 static char **pattern(void)
2029 static char **wordlist(void)
2039 while ((c
= yylex(0)) == WORD
)
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
));
2058 return block(TLIST
, t1
, t2
, NOWORDS
);
2061 static struct op
*block(int type
, struct op
*t1
, struct op
*t2
, char **wp
)
2065 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type
, T_CMD_NAMES
[type
]));
2073 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t
, t1
,
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)
2100 t
= (struct op
*) tree(sizeof(*t
));
2108 DBGPRINTF3(("NEWTP: allocated %p\n", 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
));
2119 iolist
= addword((char *) NULL
, iolist
);
2120 t
->ioact
= copyio();
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
;
2139 static char **copyw(void)
2143 wd
= getwords(wdlist
);
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
);
2162 static struct ioword
*io(int u
, int f
, char *cp
)
2166 iop
= (struct ioword
*) tree(sizeof(*iop
));
2170 iolist
= addword((char *) iop
, iolist
);
2174 static int yylex(int cf
)
2194 line
[LINELIM
- 1] = '\0';
2197 while ((c
= my_getc(0)) == ' ' || c
== '\t') /* Skip whitespace */
2202 if (any(c
, "0123456789")) {
2205 if (c1
== '<' || c1
== '>') {
2214 case '#': /* Comment, skip to next newline or End-of-string */
2215 while ((c
= my_getc(0)) != '\0' && c
!= '\n');
2220 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c
));
2224 DBGPRINTF9(("YYLEX: found $\n"));
2228 c
= collect(c
, '}');
2247 /* If more chars process them, else return NULL char */
2265 if (multiline
|| cf
& CONTIN
) {
2266 if (interactive
&& e
.iop
<= iostack
) {
2267 #if ENABLE_FEATURE_EDITING
2268 current_prompt
= cprompt
->value
;
2270 prs(cprompt
->value
);
2287 while ((c
= my_getc(0)) != '\0' && !any(c
, "`$ '\"\t;&<>()|^\n")) {
2288 if (e
.linep
>= elinep
)
2289 err("word too long");
2296 if (any(c
, "\"'`$"))
2309 yylval
.cp
= strsave(line
, areanum
);
2314 static int collect(int c
, int c1
)
2318 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c
, c1
));
2321 while ((c
= my_getc(c1
)) != c1
) {
2330 if (interactive
&& c
== '\n' && e
.iop
<= iostack
) {
2331 #if ENABLE_FEATURE_EDITING
2332 current_prompt
= cprompt
->value
;
2334 prs(cprompt
->value
);
2342 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line
));
2347 /* "multiline commands" helper func */
2348 /* see if next 2 chars form a shell multiline */
2349 static int dual(int c
)
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 */
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
)
2371 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec
));
2374 if (c
== '>' || c
== '<') {
2377 yylval
.i
= (ec
== '>' ? IOWRITE
| IOCAT
: IOHERE
);
2380 yylval
.i
= (ec
== '>' ? IOWRITE
: IOREAD
);
2381 if (c
!= '&' || yylval
.i
== IOHERE
)
2387 static char *tree(unsigned size
)
2393 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size
));
2394 prs("command line too complicated\n");
2405 /* -------- exec.c -------- */
2407 static struct op
**find1case(struct op
*t
, const char *w
)
2415 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
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
);
2425 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp
));
2428 t1
= t
->right
; /* TPAT */
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",
2441 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2445 static struct op
*findcase(struct op
*t
, const char *w
)
2449 tp
= find1case(t
, w
);
2450 return tp
!= NULL
? *tp
: NULL
;
2457 static int execute(struct op
*t
, int *pin
, int *pout
, int act
)
2460 volatile int i
, rv
, a
;
2464 struct op
*outtree_save
;
2468 /* Avoid longjmp clobbering */
2473 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
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])));
2483 wp
= (wp2
= t
->words
) != NULL
2484 ? eval(wp2
, t
->type
== TCOM
? DOALL
: DOALL
& ~DOKEY
)
2489 DBGPRINTF3(("EXECUTE: TDOT\n"));
2491 outtree_save
= outtree
;
2493 newfile(evalstr(t
->words
[0], DOALL
));
2495 t
->left
= dowholefile(TLIST
, 0);
2498 outtree
= outtree_save
;
2501 rv
= execute(t
->left
, pin
, pout
, 0);
2503 rv
= execute(t
->right
, pin
, pout
, 0);
2507 rv
= execute(t
->left
, pin
, pout
, 0);
2511 rv
= forkexec(t
, pin
, pout
, act
, wp
);
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);
2529 (void) execute(t
->left
, pin
, pout
, 0);
2530 rv
= execute(t
->right
, pin
, pout
, 0);
2535 int hinteractive
= interactive
;
2537 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2540 if (i
== 0) { /* child */
2541 signal(SIGINT
, SIG_IGN
);
2542 signal(SIGQUIT
, SIG_IGN
);
2544 signal(SIGTERM
, SIG_DFL
);
2548 xopen(bb_dev_null
, O_RDONLY
);
2550 _exit(execute(t
->left
, pin
, pout
, FEXEC
));
2552 interactive
= hinteractive
;
2554 setval(lookup("!"), putn(i
));
2569 rv
= execute(t
->left
, pin
, pout
, 0);
2571 if (t1
!= NULL
&& (rv
== 0) == (t
->type
== TAND
))
2572 rv
= execute(t1
, pin
, pout
, 0);
2583 while (*wp
++ != NULL
);
2585 vp
= lookup(t
->str
);
2586 while (setjmp(bc
.brkpt
))
2590 for (t1
= t
->left
; i
-- && *wp
!= NULL
;) {
2592 rv
= execute(t1
, pin
, pout
, 0);
2594 brklist
= brklist
->nextlev
;
2599 while (setjmp(bc
.brkpt
))
2604 while ((execute(t1
, pin
, pout
, 0) == 0) == (t
->type
== TWHILE
))
2605 rv
= execute(t
->right
, pin
, pout
, 0);
2606 brklist
= brklist
->nextlev
;
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);
2619 cp
= evalstr(t
->str
, DOSUB
| DOTRIM
);
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
);
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
));
2640 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2648 rv
= execute(t1
, pin
, pout
, 0);
2661 if (interactive
&& intr
) {
2672 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t
, 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
;
2688 static int forkexec(struct op
*t
, int *pin
, int *pout
, int act
, char **wp
)
2692 builtin_func_ptr shcom
= NULL
;
2694 const char *cp
= NULL
;
2695 struct ioword
**iopp
;
2705 struct brkcon
*hbrklist
;
2709 /* Avoid longjmp clobbering */
2719 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t
, pin
,
2721 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2722 ((t
->words
== NULL
) ? "NULL" : t
->words
[0])));
2726 rv
= -1; /* system-detected error */
2727 if (t
->type
== TCOM
) {
2728 while (*wp
++ != NULL
)
2732 /* strip all initial assignments */
2733 /* not correct wrt PATH=yyy command etc */
2735 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2737 echo(cp
? wp
: owp
);
2740 if (cp
== NULL
&& t
->ioact
== NULL
) {
2741 while ((cp
= *owp
++) != NULL
&& assign(cp
, COPYV
))
2743 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
2744 return setstatus(0);
2747 shcom
= inbuilt(cp
);
2754 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom
,
2757 if (shcom
== NULL
&& (f
& FEXEC
) == 0) {
2758 /* Save values in case the child process alters them */
2762 hinteractive
= interactive
;
2767 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2772 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
2776 if (newpid
> 0) { /* Parent */
2777 /* Restore values */
2781 interactive
= hinteractive
;
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
));
2799 signal(SIGINT
, SIG_IGN
);
2800 signal(SIGQUIT
, SIG_IGN
);
2811 while ((cp
= *owp
++) != NULL
&& assign(cp
, COPYV
))
2816 if ((pin
!= NULL
|| pout
!= NULL
) && shcom
!= NULL
&& shcom
!= doexec
) {
2817 err("piping to/from shell builtins not yet done");
2825 xmove_fd(pin
[0], 0);
2826 if (pin
[1] != 0) close(pin
[1]);
2829 xmove_fd(pout
[1], 1);
2830 if (pout
[1] != 1) close(pout
[0]);
2835 if (shcom
!= NULL
&& shcom
!= doexec
) {
2837 err(": cannot redirect shell command");
2843 if (iosetup(*iopp
++, pin
!= NULL
, pout
!= NULL
)) {
2851 i
= setstatus((*shcom
) (t
));
2854 DBGPRINTF(("FORKEXEC: returning i=%d\n", i
));
2858 /* should use FIOCEXCL */
2859 for (i
= FDBASE
; i
< NOFILE
; i
++)
2862 signal(SIGINT
, SIG_DFL
);
2863 signal(SIGQUIT
, SIG_DFL
);
2866 if (t
->type
== TPAREN
)
2867 _exit(execute(t
->left
, NOPIPE
, NOPIPE
, FEXEC
));
2871 cp
= rexecve(wp
[0], wp
, makenv(0, NULL
));
2878 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid
));
2886 * 0< 1> are ignored as required
2889 static int iosetup(struct ioword
*iop
, int pipein
, int pipeout
)
2895 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop
,
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)
2904 if (pipeout
&& iop
->io_unit
== 1)
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
);
2915 if (iop
->io_flag
& IODUP
) {
2916 if (cp
[1] || (!isdigit(*cp
) && *cp
!= '-')) {
2918 err(": illegal >& argument");
2922 iop
->io_flag
= IOCLOSE
;
2923 iop
->io_flag
&= ~(IOREAD
| IOWRITE
);
2925 switch (iop
->io_flag
) {
2927 u
= open(cp
, O_RDONLY
);
2931 case IOHERE
| IOXHERE
:
2932 u
= herein(iop
->io_name
, iop
->io_flag
& IOXHERE
);
2933 cp
= (char*)"here file";
2936 case IOWRITE
| IOCAT
:
2937 u
= open(cp
, O_WRONLY
);
2939 lseek(u
, (long) 0, SEEK_END
);
2943 u
= creat(cp
, 0666);
2947 u
= dup2(*cp
- '0', iop
->io_unit
);
2951 close(iop
->io_unit
);
2960 if (u
!= iop
->io_unit
) {
2961 dup2(u
, iop
->io_unit
);
2968 * Enter a new loop level (marked for break/continue).
2970 static void brkset(struct brkcon
*bc
)
2972 bc
->nextlev
= brklist
;
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
)
2987 int oheedint
= heedint
;
2994 if (errno
!= EINTR
|| canintr
)
2999 if (rv
< ARRAY_SIZE(signame
)) {
3000 if (signame
[rv
] != NULL
) {
3001 if (pid
!= lastpid
) {
3008 if (pid
!= lastpid
) {
3017 prs(" - core dumped");
3018 if (rv
>= ARRAY_SIZE(signame
) || signame
[rv
])
3024 } while (pid
!= lastpid
);
3039 static int setstatus(int s
)
3042 setval(lookup("?"), putn(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
)
3056 int eacces
= 0, asis
= 0;
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
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') {
3075 for (; *sp
!= '\0'; tp
++) {
3078 asis
= (*sp
== '\0');
3084 for (i
= 0; (*tp
++ = c
[i
++]) != '\0';);
3086 DBGPRINTF3(("REXECVE: e.linep is %s\n", e
.linep
));
3088 execve(e
.linep
, v
, envp
);
3095 execve(DEFAULT_SHELL
, v
, envp
);
3100 return (char *) bb_msg_memory_exhausted
;
3103 return "argument list too long";
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
*))
3120 struct wdblock
*swdlist
;
3121 struct wdblock
*siolist
;
3127 /* Avoid longjmp clobbering */
3131 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3132 areanum
, outtree
, failpt
));
3142 if (newenv(setjmp(errpt
)) == 0) {
3149 if (setjmp(failpt
) == 0 && yyparse() == 0)
3150 rv
= execute(outtree
, NOPIPE
, NOPIPE
, 0);
3153 DBGPRINTF(("RUN: error from newenv()!\n"));
3160 freearea(areanum
--);
3165 /* -------- do.c -------- */
3168 * built-in commands: doX
3171 static int dohelp(struct op
*t
)
3174 const struct builtincmd
*x
;
3176 puts("\nBuilt-in commands:\n"
3177 "-------------------");
3182 col
+= printf("%c%s", ((col
== 0) ? '\t' : ' '), x
->name
);
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
);
3204 return EXIT_SUCCESS
;
3207 static int dolabel(struct op
*t
)
3212 static int dochdir(struct op
*t
)
3214 const char *cp
, *er
;
3218 cp
= homedir
->value
;
3221 er
= ": no home directory";
3226 er
= ": bad directory";
3228 prs(cp
!= NULL
? cp
: "cd");
3233 static int doshift(struct op
*t
)
3237 n
= t
->words
[1] ? getn(t
->words
[1]) : 1;
3239 err("nothing to shift");
3245 setval(lookup("#"), putn(dolc
));
3250 * execute login and newgrp directly
3252 static int dologin(struct op
*t
)
3257 signal(SIGINT
, SIG_DFL
);
3258 signal(SIGQUIT
, SIG_DFL
);
3260 cp
= rexecve(t
->words
[0], t
->words
, makenv(0, NULL
));
3267 static int doumask(struct op
*t
)
3276 for (n
= 3 * 4; (n
-= 3) >= 0;)
3277 fputc('0' + ((i
>> n
) & 07), stderr
);
3278 fputc('\n', stderr
);
3280 /* huh??? '8','9' are not allowed! */
3281 for (n
= 0; *cp
>= '0' && *cp
<= '9'; cp
++)
3282 n
= n
* 8 + (*cp
- '0');
3288 static int doexec(struct op
*t
)
3295 for (i
= 0; (t
->words
[i
] = t
->words
[i
+ 1]) != NULL
; i
++);
3301 if (setjmp(failpt
) == 0)
3302 execute(t
, NOPIPE
, NOPIPE
, FEXEC
);
3308 static int dodot(struct op
*t
)
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
)));
3320 DBGPRINTF(("DODOT: bad args, ret 0\n"));
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
)));
3333 while (*sp
&& (*tp
= *sp
++) != ':')
3338 for (i
= 0; (*tp
++ = cp
[i
++]) != '\0';);
3341 i
= open(e
.linep
, O_RDONLY
);
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
));
3361 static int dowait(struct op
*t
)
3373 setstatus(waitfor(i
, 1));
3377 static int doread(struct op
*t
)
3383 if (t
->words
[1] == NULL
) {
3384 err("Usage: read name ...");
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
))
3393 if (nl
|| (wp
[1] && any(*cp
, ifs
->value
)))
3399 setval(lookup(*wp
), e
.linep
);
3404 static int doeval(struct op
*t
)
3406 return RUN(awordlist
, t
->words
+ 1, wdchar
);
3409 static int dotrap(struct op
*t
)
3414 if (t
->words
[1] == NULL
) {
3415 for (i
= 0; i
<= _NSIG
; i
++)
3424 resetsig
= isdigit(*t
->words
[1]);
3425 for (i
= resetsig
? 1 : 2; t
->words
[i
] != NULL
; ++i
) {
3426 n
= getsig(t
->words
[i
]);
3430 if (*t
->words
[1] != '\0') {
3431 trap
[n
] = strsave(t
->words
[1], 0);
3440 setsig(n
, n
== SIGQUIT
? SIG_IGN
: SIG_DFL
);
3448 static int getsig(char *s
)
3453 if (n
< 0 || n
> _NSIG
) {
3454 err("trap: bad signal number");
3460 static void setsig(int n
, sighandler_t f
)
3464 if (signal(n
, SIG_IGN
) != SIG_IGN
|| ourtrap
[n
]) {
3470 static int getn(char *as
)
3481 for (n
= 0; isdigit(*s
); s
++)
3482 n
= (n
* 10) + (*s
- '0');
3485 err(": bad number");
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
)
3505 nl
= cp
== NULL
? 1 : getn(cp
);
3512 brklist
= bc
->nextlev
;
3515 err("bad break/continue level");
3519 longjmp(bc
->brkpt
, 1);
3523 static int doexit(struct op
*t
)
3530 setstatus(getn(cp
));
3532 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t
));
3539 static int doexport(struct op
*t
)
3541 rdexp(t
->words
+ 1, export
, EXPORT
);
3545 static int doreadonly(struct op
*t
)
3547 rdexp(t
->words
+ 1, ronly
, RONLY
);
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
));
3557 for (; *wp
!= NULL
; wp
++) {
3558 if (isassign(*wp
)) {
3562 for (cp
= *wp
; *cp
!= '='; cp
++);
3574 static void badid(char *s
)
3577 err(": bad identifier");
3580 static int doset(struct op
*t
)
3588 for (vp
= vlist
; vp
; vp
= vp
->next
)
3589 varput(vp
->name
, 1);
3593 /* bad: t->words++; */
3594 for (n
= 0; (t
->words
[n
] = t
->words
[n
+ 1]) != NULL
; n
++);
3596 FLAG
['x'] = FLAG
['v'] = 0;
3606 if (*cp
>= 'a' && *cp
<= 'z')
3615 t
->words
[0] = dolv
[0];
3616 for (n
= 1; t
->words
[n
]; n
++)
3617 setarea((char *) t
->words
[n
], 0);
3620 setval(lookup("#"), putn(dolc
));
3621 setarea((char *) (dolv
- 1), 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
)
3642 long clk_tck
= sysconf(_SC_CLK_TCK
);
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
);
3658 /* -------- eval.c -------- */
3663 * blank interpretation
3668 static char **eval(char **ap
, int f
)
3676 /* Avoid longjmp clobbering */
3681 DBGPRINTF4(("EVAL: enter, f=%d\n", f
));
3687 if (newenv(setjmp(errpt
)) == 0) {
3688 while (*ap
&& isassign(*ap
))
3689 expand(*ap
++, &wb
, f
& ~DOGLOB
);
3691 for (wf
= ap
; *wf
; 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
);
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
)
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
)
3734 /* Avoid longjmp clobbering */
3738 DBGPRINTF3(("EXPAND: enter, f=%d\n", f
));
3745 if (!anys("$`'\"", cp
) && !anys(ifs
->value
, cp
)
3746 && ((f
& DOGLOB
) == 0 || !anys("[*?", cp
))
3748 xp
= strsave(cp
, areanum
);
3751 *wbp
= addword(xp
, *wbp
);
3755 if (newenv(setjmp(errpt
)) == 0) {
3756 PUSHIO(aword
, cp
, strchar
);
3758 while ((xp
= blank(f
)) && gflg
== 0) {
3760 xp
= strsave(xp
, areanum
);
3761 if ((f
& DOGLOB
) == 0) {
3764 *wbp
= addword(xp
, *wbp
);
3766 *wbp
= glob(xp
, *wbp
);
3774 static char *evalstr(char *cp
, int f
)
3778 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp
, f
));
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)!
3798 * Blank interpretation and quoting
3800 static char *blank(int f
)
3804 int scanequals
, foundequals
;
3806 DBGPRINTF3(("BLANK: enter, f=%d\n", f
));
3809 scanequals
= f
& DOKEY
;
3813 c
= subgetc('"', foundequals
);
3822 if (f
& DOBLANK
&& any(c
, ifs
->value
))
3831 for (c1
= c
; (c
= subgetc(c1
, 1)) != c1
;) {
3834 if (c
== '\'' || !any(c
, "$`\""))
3841 if (!isalpha(c
) && c
!= '_')
3844 c
= subgetc('"', foundequals
);
3846 f
& (DOBLANK
&& any(c
, ifs
->value
)) ||
3847 (!INSUB() && any(c
, "\"'"))) {
3858 } else if (!isalnum(c
) && c
!= '_')
3868 * Get characters, substituting for ` and $
3870 static int subgetc(char ec
, int quoted
)
3874 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted
));
3878 if (!INSUB() && ec
!= '\'') {
3880 if (grave(quoted
) == 0)
3882 e
.iop
->task
= XGRAVE
;
3888 e
.iop
->task
= XDOLL
;
3897 * Prepare to generate the string returned by ${} substitution.
3899 static int dollar(int quoted
)
3904 char *s
, c
, *cp
= NULL
;
3907 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted
));
3913 if (isalpha(c
) || c
== '_') {
3914 while ((c
= readc()) != 0 && (isalnum(c
) || c
== '_'))
3915 if (e
.linep
< elinep
)
3922 otask
= e
.iop
->task
;
3924 e
.iop
->task
= XOTHER
;
3925 while ((c
= subgetc('"', 0)) != 0 && c
!= '}' && c
!= '\n')
3926 if (e
.linep
< elinep
)
3929 e
.iop
->task
= otask
;
3936 if (e
.linep
>= elinep
) {
3937 err("string in ${} too long");
3943 for (cp
= s
+ 1; *cp
; cp
++)
3944 if (any(*cp
, "=-+?")) {
3949 if (s
[1] == 0 && (*s
== '*' || *s
== '@')) {
3951 /* currently this does not distinguish $* and $@ */
3952 /* should check dollar */
3954 PUSHIO(awordlist
, dolv
+ 1, dolchar
);
3956 } else { /* trap the nasty ${=} */
3967 err("cannot use ${...=...} with $n");
3976 dolp
= strsave(cp
, areanum
);
3981 prs("missing value for ");
3988 } else if (c
== '+')
3989 dolp
= strsave(cp
, areanum
);
3990 if (FLAG
['u'] && dolp
== null
) {
3991 prs("unset variable: ");
3996 PUSHIO(aword
, dolp
, quoted
? qstrchar
: strchar
);
4001 * Run the command in `...` and read its output.
4004 static int grave(int quoted
)
4006 /* moved to G: static char child_cmd[LINELIM]; */
4017 char *argument_list
[4];
4018 struct wdblock
*wb
= NULL
;
4021 /* Avoid longjmp clobbering */
4025 for (cp
= e
.iop
->argp
->aword
; *cp
!= '`'; cp
++) {
4027 err("no closing `");
4032 /* string copy with dollar expansion */
4033 src
= e
.iop
->argp
->aword
;
4038 while ((*src
!= '`') && (count
< LINELIM
)) {
4043 if (*src
== '$' && !ignore
&& !ignore_once
) {
4045 char var_name
[LINELIM
];
4046 char alt_value
[LINELIM
];
4059 var_name
[var_index
++] = *src
++;
4060 while (isalnum(*src
) || *src
=='_')
4061 var_name
[var_index
++] = *src
++;
4062 var_name
[var_index
] = 0;
4075 err("unclosed ${\n");
4080 while (*src
&& (*src
!= '}')) {
4081 alt_value
[alt_index
++] = *src
++;
4083 alt_value
[alt_index
] = 0;
4085 err("unclosed ${\n");
4092 if (isalpha(*var_name
)) {
4093 /* let subshell handle it instead */
4095 char *namep
= var_name
;
4103 char *altp
= alt_value
;
4111 wb
= addword(lookup(var_name
)->name
, wb
);
4115 vp
= lookup(var_name
);
4116 if (vp
->value
!= null
)
4117 value
= (operator == '+') ?
4118 alt_value
: vp
->value
;
4119 else if (operator == '?') {
4122 } else if (alt_index
&& (operator != '+')) {
4124 if (operator == '=')
4129 while (*value
&& (count
< LINELIM
)) {
4142 if (openpipe(pf
) < 0)
4145 while ((i
= vfork()) == -1 && errno
== EAGAIN
);
4147 DBGPRINTF3(("GRAVE: i is %p\n", io
));
4151 err((char *) bb_msg_memory_exhausted
);
4155 waitpid(i
, NULL
, 0);
4156 e
.iop
->argp
->aword
= ++cp
;
4158 PUSHIO(afile
, remap(pf
[0]),
4159 (int (*)(struct ioarg
*)) ((quoted
) ? qgravechar
: gravechar
));
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
)
4168 /* Testcase where below checks are needed:
4169 * close stdout & run this script:
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]);
4189 static char *unquote(char *as
)
4200 /* -------- glob.c -------- */
4206 #define scopy(x) strsave((x), areanum)
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
)
4221 for (pp
= cp
; *pp
; pp
++)
4224 else if (!any(*pp
& ~QUOTE
, spcl
))
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
);
4236 nl
= addword(scopy(cl
->w_words
[i
]), nl
);
4238 for (i
= 0; i
< cl
->w_nword
; i
++)
4239 DELETE(cl
->w_words
[i
]);
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
);
4246 for (i
= 0; i
< cl
->w_nword
; i
++)
4247 wb
= addword(cl
->w_words
[i
], wb
);
4252 wb
= addword(unquote(cp
), wb
);
4256 static void globname(char *we
, char *pp
)
4259 char *name
, *gp
, *dp
;
4263 char dname
[NAME_MAX
+ 1];
4266 for (np
= we
; np
!= pp
; pp
--)
4269 for (dp
= cp
= space((int) (pp
- np
) + 3); np
< pp
;)
4273 for (gp
= cp
= space(strlen(pp
) + 1); *np
&& *np
!= '/';)
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)
4289 strncpy(dname
, de
->d_name
, NAME_MAX
);
4290 if (dname
[0] == '.')
4293 for (k
= 0; k
< NAME_MAX
; k
++)
4294 if (any(dname
[k
], spcl
))
4296 if (gmatch(dname
, gp
)) {
4297 name
= generate(we
, pp
, dname
, np
);
4298 if (*np
&& !anys(np
, spcl
)) {
4299 if (stat(name
, &dbuf
)) {
4304 nl
= addword(name
, nl
);
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
)
4322 p
= op
= space((int)(end1
- start1
) + strlen(middle
) + strlen(end
) + 2);
4323 for (xp
= start1
; xp
!= end1
;)
4325 for (xp
= middle
; (*op
++ = *xp
++) != '\0';);
4327 for (xp
= end
; (*op
++ = *xp
++) != '\0';);
4331 static int anyspcl(struct wdblock
*wb
)
4337 for (i
= 0; i
< wb
->w_nword
; i
++)
4338 if (anys(spcl
, *wd
++))
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
)
4355 wb
= (struct wdblock
*) space(sizeof(*wb
) + nw
* sizeof(char *));
4361 static struct wdblock
*addword(char *wd
, struct wdblock
*wb
)
4363 struct wdblock
*wb2
;
4367 wb
= newword(NSTART
);
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 *));
4377 wb
->w_words
[wb
->w_nword
++] = wd
;
4381 static char **getwords(struct wdblock
*wb
)
4388 if (wb
->w_nword
== 0) {
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 */
4398 static int (*func
) (char *, char *);
4401 static void glob3(char *i
, char *j
, char *k
)
4403 char *index1
, *index2
, *index3
;
4413 *index1
++ = *index3
;
4414 *index3
++ = *index2
;
4419 static void glob2(char *i
, char *j
)
4421 char *index1
, *index2
, c
;
4429 *index1
++ = *index2
;
4434 static void glob1(char *base
, char *lim
)
4445 n
= (int) (lim
- base
);
4448 n
= v2
* (n
/ (2 * v2
));
4449 hptr
= lptr
= base
+ n
;
4454 c
= (*func
) (i
, lptr
);
4468 c
= (*func
) (hptr
, j
);
4492 if (lptr
- base
>= lim
- hptr
) {
4493 glob1(hptr
+ v2
, lim
);
4508 static void glob0(char *a0
, unsigned a1
, int a2
, int (*a3
) (char *, char *))
4512 glob1(a0
, a0
+ a1
* a2
);
4516 /* -------- io.c -------- */
4522 static int my_getc(int ec
)
4526 if (e
.linep
> elinep
) {
4527 while ((c
= readc()) != '\n' && c
);
4528 err("input line too long");
4533 if ((ec
!= '\'') && (ec
!= '`') && (e
.iop
->task
!= XGRAVE
)) {
4536 if (c
== '\n' && ec
!= '\"')
4544 static void unget(int c
)
4546 if (e
.iop
>= e
.iobase
)
4550 static int eofc(void)
4552 return e
.iop
< e
.iobase
|| (e
.iop
->peekc
== 0 && e
.iop
->prev
== 0);
4555 static int readc(void)
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
));
4568 if (e
.iop
->prev
!= 0) {
4569 c
= (*e
.iop
->iofn
)(e
.iop
->argp
, e
.iop
);
4575 if (e
.iop
== iostack
)
4580 if (e
.iop
->task
== XIO
&& e
.iop
->prev
!= '\n') {
4582 if (e
.iop
== iostack
)
4587 if (e
.iop
->task
== XIO
) {
4592 if (interactive
&& e
.iop
== iostack
+ 1) {
4593 #if ENABLE_FEATURE_EDITING
4594 current_prompt
= prompt
->value
;
4602 if (e
.iop
>= iostack
) {
4603 RCPRINTF(("READC: return 0, e.iop %p\n", e
.iop
));
4607 DBGPRINTF(("READC: leave()...\n"));
4614 static void ioecho(char c
)
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
]) {
4629 err("Shell input nested too deeply");
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
)
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
;
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';
4675 if (fn
== filechar
|| fn
== linechar
)
4677 else if (fn
== (int (*)(struct ioarg
*)) gravechar
4678 || fn
== (int (*)(struct ioarg
*)) qgravechar
)
4679 e
.iop
->task
= XGRAVE
;
4681 e
.iop
->task
= XOTHER
;
4684 static struct io
*setbase(struct io
*ip
)
4694 * Input generating functions
4698 * Produce the characters of a string, then a newline, then EOF.
4700 static int nlchar(struct ioarg
*ap
)
4704 if (ap
->aword
== NULL
)
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
)
4733 ap
->awordlist
= NULL
;
4738 * Return the characters of a list of words,
4739 * producing a space between them.
4741 static int dolchar(struct ioarg
*ap
)
4745 wp
= *ap
->awordlist
++;
4747 PUSHIO(aword
, wp
, *ap
->awordlist
== NULL
? strchar
: xxchar
);
4753 static int xxchar(struct ioarg
*ap
)
4757 if (ap
->aword
== NULL
)
4768 * Produce the characters from a single word (string).
4770 static int strchar(struct ioarg
*ap
)
4772 if (ap
->aword
== NULL
)
4774 return *ap
->aword
++;
4778 * Produce quoted characters from a single word (string).
4780 static int qstrchar(struct ioarg
*ap
)
4784 if (ap
->aword
== NULL
)
4793 * Return the characters from a file.
4795 static int filechar(struct ioarg
*ap
)
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
) {
4805 lseek(ap
->afile
, ap
->afpos
, SEEK_SET
);
4807 i
= safe_read(ap
->afile
, bp
->buf
, sizeof(bp
->buf
));
4815 bp
->ebufp
= bp
->bufp
+ i
;
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
);
4831 c
= filechar_cmdbuf
[position
];
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
)
4847 if (read(ap
->afile
, &c
, sizeof(c
)) != sizeof(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
)
4862 c
= qgravechar(ap
, iop
) & ~QUOTE
;
4868 static int qgravechar(struct ioarg
*ap
, struct io
*iop
)
4872 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap
, iop
));
4877 return '\n' | QUOTE
;
4881 } else if ((c
= filechar(ap
)) == '\n') {
4883 while ((c
= filechar(ap
)) == '\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
)
4905 ap
->afile
= -1; /* illegal value */
4912 * remap fd into Shell's fd space
4914 static int remap(int fd
)
4920 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd
, e
.iofd
));
4923 for (i
= 0; i
< NOFILE
; i
++)
4930 } while (fd
>= 0 && fd
< e
.iofd
);
4932 for (i
= 0; i
< NOFILE
; i
++)
4937 err("too many files open in shell");
4943 static int openpipe(int *pv
)
4949 err("can't create pipe - try again");
4953 static void closepipe(int *pv
)
4962 /* -------- here.c -------- */
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
));
4978 h
->h_tag
= evalstr(s
, DOSUB
);
4988 for (lh
= inhere
; lh
!= NULL
; lh
= lh
->h_next
) {
4989 if (lh
->h_next
== 0) {
4995 iop
->io_flag
|= IOHERE
| IOXHERE
;
4996 for (s
= h
->h_tag
; *s
; s
++) {
4998 iop
->io_flag
&= ~IOXHERE
;
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 */
5017 hp
->h_next
= acthere
;
5023 static void readhere(char **name
, char *s
, int ec
)
5026 char tname
[30] = ".msh_XXXXXX";
5029 char myline
[LINELIM
+ 1];
5032 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name
, s
));
5034 tf
= mkstemp(tname
);
5038 *name
= strsave(tname
, areanum
);
5040 if (newenv(setjmp(errpt
)) != 0)
5043 pushio(e
.iop
->argp
, (int (*)(struct ioarg
*)) e
.iop
->iofn
);
5046 if (interactive
&& e
.iop
<= iostack
) {
5047 #if ENABLE_FEATURE_EDITING
5048 current_prompt
= cprompt
->value
;
5050 prs(cprompt
->value
);
5054 while ((c
= my_getc(ec
)) != '\n' && c
) {
5057 if (thenext
>= &myline
[LINELIM
]) {
5064 if (strcmp(s
, myline
) == 0 || c
== 0)
5067 write(tf
, myline
, (int) (thenext
- myline
));
5070 prs("here document `");
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
)
5089 /* Avoid longjmp clobbering */
5095 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname
, xdoll
));
5097 hf
= open(hname
, O_RDONLY
);
5103 char tname
[30] = ".msh_XXXXXX";
5106 tf
= mkstemp(tname
);
5110 if (newenv(setjmp(errpt
)) == 0) {
5111 PUSHIO(afile
, hf
, herechar
);
5113 while ((c
= subgetc(0, 0)) != 0) {
5115 write(tf
, &c
, sizeof c
);
5121 tf
= open(tname
, O_RDONLY
);
5128 static void scraphere(void)
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
);
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
));
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
);
5154 acthere
= h
->h_next
;
5156 hl
->h_next
= h
->h_next
;
5162 /* -------- sh.c -------- */
5167 int msh_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
5168 int msh_main(int argc
, char **argv
)
5174 int (*iof
) (struct ioarg
*);
5176 PTR_TO_GLOBALS
= xzalloc(sizeof(G
));
5177 sharedbuf
.id
= AFID_NOBUF
;
5178 mainbuf
.id
= AFID_NOBUF
;
5180 elinep
= line
+ sizeof(line
) - 5;
5182 #if ENABLE_FEATURE_EDITING
5183 line_input_state
= new_line_input_t(FOR_SHELL
);
5186 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc
, environ
));
5192 assign(*ap
++, !COPYV
);
5193 for (ap
= environ
; *ap
;)
5194 export(lookup(*ap
++));
5199 shell
= lookup("SHELL");
5200 if (shell
->value
== null
)
5201 setval(shell
, (char *)DEFAULT_SHELL
);
5204 homedir
= lookup("HOME");
5205 if (homedir
->value
== null
)
5206 setval(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 */
5215 setval(path
, bb_default_root_path
);
5217 setval(path
, bb_default_path
);
5221 ifs
= lookup("IFS");
5222 if (ifs
->value
== null
)
5223 setval(ifs
, " \t\n");
5226 mshdbg_var
= lookup("MSHDEBUG");
5227 if (mshdbg_var
->value
== null
)
5228 setval(mshdbg_var
, "0");
5231 prompt
= lookup("PS1");
5232 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5233 if (prompt
->value
== null
)
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
)
5244 setval(cprompt
, "> ");
5250 if (argv
[0][0] == '-' && argv
[0][1] != '\0') {
5251 for (s
= argv
[0] + 1; *s
; s
++)
5254 prompt
->status
&= ~EXPORT
;
5255 cprompt
->status
&= ~EXPORT
;
5257 setval(cprompt
, "");
5260 PUSHIO(aword
, *++argv
, iof
= nlchar
);
5268 /* standard input */
5272 prompt
->status
&= ~EXPORT
;
5280 if (*s
>= 'a' && *s
<= 'z')
5288 if (iof
== filechar
&& --argc
> 0) {
5290 setval(cprompt
, "");
5291 prompt
->status
&= ~EXPORT
;
5292 cprompt
->status
&= ~EXPORT
;
5294 /* Shell is non-interactive, activate printf-based debug */
5296 mshdbg
= (int) (((char) (mshdbg_var
->value
[0])) - '0');
5300 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5304 exit(1); /* Exit on error */
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
) {
5315 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
5317 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner
);
5319 printf("\n\n%s built-in shell (msh)\n", bb_banner
);
5321 printf("Enter 'help' for a list of built-in commands.\n\n");
5326 signal(SIGQUIT
, qflag
);
5327 if (name
&& name
[0] == '-') {
5329 f
= open(".profile", O_RDONLY
);
5332 f
= open("/etc/profile", O_RDONLY
);
5337 signal(SIGTERM
, sig
);
5339 if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
5340 signal(SIGINT
, onintr
);
5345 for (ap
= ++argv
; --argc
> 0;) {
5347 if (assign(*ap
, !COPYV
)) {
5348 dolc
--; /* keyword */
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
));
5359 if (interactive
&& e
.iop
<= iostack
) {
5360 #if ENABLE_FEATURE_EDITING
5361 current_prompt
= prompt
->value
;
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.