X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=shell%2Fmsh.c;h=aa6fb1d2613acdce30237ae398b6a51bc2b233d3;hb=29eb3599e4014c225365f2c5539cf8a3ef46136e;hp=4d1e84cf0139ac5fd7fdf091fd856363eb455346;hpb=51742f4bb0c57a4d5063ece9437a2f34a42e52c8;p=oweals%2Fbusybox.git diff --git a/shell/msh.c b/shell/msh.c index 4d1e84cf0..aa6fb1d26 100644 --- a/shell/msh.c +++ b/shell/msh.c @@ -36,18 +36,19 @@ # define bb_dev_null "/dev/null" # define DEFAULT_SHELL "/proc/self/exe" # define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe" -# define BB_BANNER "busybox standalone" +# define bb_banner "busybox standalone" # define ENABLE_FEATURE_SH_STANDALONE 0 # define bb_msg_memory_exhausted "memory exhausted" # define xmalloc(size) malloc(size) # define msh_main(argc,argv) main(argc,argv) # define safe_read(fd,buf,count) read(fd,buf,count) +# define nonblock_safe_read(fd,buf,count) read(fd,buf,count) # define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1]) # define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1]) # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) -static char *find_applet_by_name(const char *applet) +static int find_applet_by_name(const char *applet) { - return NULL; + return -1; } static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) { @@ -58,10 +59,10 @@ static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) for (i = 1000000000; i; i /= 10) { res = n / i; if (res || out || i == 1) { - if (!--buflen) break; - out++; - n -= res*i; - *buf++ = '0' + res; + if (!--buflen) break; + out++; + n -= res*i; + *buf++ = '0' + res; } } } @@ -83,14 +84,13 @@ static char *itoa(int n) return local_buf; } #else -# include "busybox.h" -extern char **environ; +# include "busybox.h" /* for applet_names */ #endif -/*#define MSHDEBUG 1*/ +//#define MSHDEBUG 4 #ifdef MSHDEBUG -int mshdbg = MSHDEBUG; +static int mshdbg = MSHDEBUG; #define DBGPRINTF(x) if (mshdbg>0) printf x #define DBGPRINTF0(x) if (mshdbg>0) printf x @@ -104,7 +104,7 @@ int mshdbg = MSHDEBUG; #define DBGPRINTF8(x) if (mshdbg>8) printf x #define DBGPRINTF9(x) if (mshdbg>9) printf x -int mshdbg_rc = 0; +static int mshdbg_rc = 0; #define RCPRINTF(x) if (mshdbg_rc) printf x @@ -152,15 +152,14 @@ int mshdbg_rc = 0; /* * values returned by wait */ -#define WAITSIG(s) ((s)&0177) -#define WAITVAL(s) (((s)>>8)&0377) -#define WAITCORE(s) (((s)&0200)!=0) +#define WAITSIG(s) ((s) & 0177) +#define WAITVAL(s) (((s) >> 8) & 0377) +#define WAITCORE(s) (((s) & 0200) != 0) /* * library and system definitions */ -typedef void xint; /* base type of jmp_buf, for not broken compilers */ - +typedef void xint; /* base type of jmp_buf, for not broken compilers */ /* * shell components @@ -170,25 +169,24 @@ typedef void xint; /* base type of jmp_buf, for not broken compilers */ #define NOWORDS ((char **)NULL) #define NOPIPE ((int *)NULL) - /* * redirection */ struct ioword { - short io_unit; /* unit affected */ - short io_flag; /* action (below) */ - char *io_name; /* file name */ + smallint io_flag; /* action (below) */ + int io_fd; /* fd affected */ + char *io_name; /* file name */ }; -#define IOREAD 1 /* < */ -#define IOHERE 2 /* << (here file) */ -#define IOWRITE 4 /* > */ -#define IOCAT 8 /* >> */ -#define IOXHERE 16 /* ${}, ` in << */ -#define IODUP 32 /* >&digit */ -#define IOCLOSE 64 /* >&- */ +#define IOREAD 1 /* < */ +#define IOHERE 2 /* << (here file) */ +#define IOWRITE 4 /* > */ +#define IOCAT 8 /* >> */ +#define IOXHERE 16 /* ${}, ` in << */ +#define IODUP 32 /* >&digit */ +#define IOCLOSE 64 /* >&- */ -#define IODEFAULT (-1) /* token for default IO unit */ +#define IODEFAULT (-1) /* "default" IO fd */ /* @@ -196,32 +194,32 @@ struct ioword { * Might eventually use a union. */ struct op { - int type; /* operation type, see below */ - char **words; /* arguments to a command */ - struct ioword **ioact; /* IO actions (eg, < > >>) */ + smallint op_type; /* operation type, see Txxxx below */ + char **op_words; /* arguments to a command */ + struct ioword **ioact; /* IO actions (eg, < > >>) */ struct op *left; struct op *right; - char *str; /* identifier for case and for */ + char *str; /* identifier for case and for */ }; -#define TCOM 1 /* command */ -#define TPAREN 2 /* (c-list) */ -#define TPIPE 3 /* a | b */ -#define TLIST 4 /* a [&;] b */ -#define TOR 5 /* || */ -#define TAND 6 /* && */ -#define TFOR 7 -#define TDO 8 -#define TCASE 9 -#define TIF 10 -#define TWHILE 11 -#define TUNTIL 12 -#define TELIF 13 -#define TPAT 14 /* pattern in case */ -#define TBRACE 15 /* {c-list} */ -#define TASYNC 16 /* c & */ +#define TCOM 1 /* command */ +#define TPAREN 2 /* (c-list) */ +#define TPIPE 3 /* a | b */ +#define TLIST 4 /* a [&;] b */ +#define TOR 5 /* || */ +#define TAND 6 /* && */ +#define TFOR 7 +#define TDO 8 +#define TCASE 9 +#define TIF 10 +#define TWHILE 11 +#define TUNTIL 12 +#define TELIF 13 +#define TPAT 14 /* pattern in case */ +#define TBRACE 15 /* {c-list} */ +#define TASYNC 16 /* c & */ /* Added to support "." file expansion */ -#define TDOT 17 +#define TDOT 17 /* Strings for names to make debug easier */ #ifdef MSHDEBUG @@ -247,28 +245,18 @@ static const char *const T_CMD_NAMES[] = { }; #endif -/* - * actions determining the environment of a process - */ -#define BIT(i) (1<<(i)) -#define FEXEC BIT(0) /* execute without forking */ - -#define AREASIZE (90000) +#define AREASIZE (90000) /* * flags to control evaluation of words */ -#define DOSUB 1 /* interpret $, `, and quotes */ -#define DOBLANK 2 /* perform blank interpretation */ -#define DOGLOB 4 /* interpret [?* */ -#define DOKEY 8 /* move words with `=' to 2nd arg. list */ -#define DOTRIM 16 /* trim resulting string */ - -#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) - +#define DOSUB 1 /* interpret $, `, and quotes */ +#define DOBLANK 2 /* perform blank interpretation */ +#define DOGLOB 4 /* interpret [?* */ +#define DOKEY 8 /* move words with `=' to 2nd arg. list */ +#define DOTRIM 16 /* trim resulting string */ -/* PROTOTYPES */ -static int newfile(char *s); +#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) struct brkcon { @@ -277,25 +265,9 @@ struct brkcon { }; -/* - * flags: - * -e: quit on error - * -k: look for name=value everywhere on command line - * -n: no execution - * -t: exit after reading and executing one command - * -v: echo as read - * -x: trace - * -u: unset variables net diagnostic - */ -static char flags['z' - 'a' + 1]; -/* this looks weird, but is OK ... we index flag with 'a'...'z' */ -static char *flag = flags - 'a'; - -/* moved to G: static char *trap[_NSIG + 1]; */ -/* moved to G: static char ourtrap[_NSIG + 1]; */ -static int trapset; /* trap pending */ +static smallint trapset; /* trap pending (signal number) */ -static int yynerrs; /* yacc */ +static smallint yynerrs; /* yacc (flag) */ /* moved to G: static char line[LINELIM]; */ @@ -333,13 +305,13 @@ static void runtrap(int i); /* -------- area stuff -------- */ -#define REGSIZE sizeof(struct region) -#define GROWBY (256) -/* #define SHRINKBY (64) */ -#undef SHRINKBY -#define FREE (32767) -#define BUSY (0) -#define ALIGN (sizeof(int)-1) +#define REGSIZE sizeof(struct region) +#define GROWBY (256) +/* #define SHRINKBY (64) */ +#undef SHRINKBY +#define FREE (32767) +#define BUSY (0) +#define ALIGN (sizeof(int)-1) struct region { @@ -426,12 +398,6 @@ struct var { static int yyparse(void); -static int execute(struct op *t, int *pin, int *pout, int act); - - -#define AFID_NOBUF (~0) -#define AFID_ID 0 - /* -------- io.h -------- */ /* io buffer */ @@ -448,7 +414,7 @@ struct ioarg { char **awordlist; int afile; /* file descriptor */ unsigned afid; /* buffer id */ - long afpos; /* file position */ + off_t afpos; /* file position */ struct iobuf *afbuf; /* buffer for this file */ }; @@ -462,23 +428,11 @@ struct io { char xchar; /* for `'s */ char task; /* reason for pushed IO */ }; - -#define XOTHER 0 /* none of the below */ -#define XDOLL 1 /* expanding ${} */ -#define XGRAVE 2 /* expanding `'s */ -#define XIO 3 /* file IO */ - -/* in substitution */ -#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL) - -static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */ -/* moved to G: static struct ioarg ioargstack[NPUSH]; */ -static struct io iostack[NPUSH]; -/* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */ -/* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */ -static unsigned bufid = AFID_ID; /* buffer id counter */ - -#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) +/* ->task: */ +#define XOTHER 0 /* none of the below */ +#define XDOLL 1 /* expanding ${} */ +#define XGRAVE 2 /* expanding `'s */ +#define XIO 3 /* file IO */ /* @@ -535,35 +489,37 @@ static char **getwords(struct wdblock *wb); /* -------- misc stuff -------- */ -static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); +static int dolabel(struct op *t, char **args); +static int dohelp(struct op *t, char **args); +static int dochdir(struct op *t, char **args); +static int doshift(struct op *t, char **args); +static int dologin(struct op *t, char **args); +static int doumask(struct op *t, char **args); +static int doexec(struct op *t, char **args); +static int dodot(struct op *t, char **args); +static int dowait(struct op *t, char **args); +static int doread(struct op *t, char **args); +static int doeval(struct op *t, char **args); +static int dotrap(struct op *t, char **args); +static int dobreak(struct op *t, char **args); +static int doexit(struct op *t, char **args); +static int doexport(struct op *t, char **args); +static int doreadonly(struct op *t, char **args); +static int doset(struct op *t, char **args); +static int dotimes(struct op *t, char **args); +static int docontinue(struct op *t, char **args); + +static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp); +static int execute(struct op *t, int *pin, int *pout, int no_fork); static int iosetup(struct ioword *iop, int pipein, int pipeout); static void brkset(struct brkcon *bc); -static int dolabel(struct op *t); -static int dohelp(struct op *t); -static int dochdir(struct op *t); -static int doshift(struct op *t); -static int dologin(struct op *t); -static int doumask(struct op *t); -static int doexec(struct op *t); -static int dodot(struct op *t); -static int dowait(struct op *t); -static int doread(struct op *t); -static int doeval(struct op *t); -static int dotrap(struct op *t); static int getsig(char *s); static void setsig(int n, sighandler_t f); static int getn(char *as); -static int dobreak(struct op *t); -static int docontinue(struct op *t); static int brkcontin(char *cp, int val); -static int doexit(struct op *t); -static int doexport(struct op *t); -static int doreadonly(struct op *t); static void rdexp(char **wp, void (*f) (struct var *), int key); static void badid(char *s); -static int doset(struct op *t); static void varput(char *s, int out); -static int dotimes(struct op *t); static int expand(const char *cp, struct wdblock **wbp, int f); static char *blank(int f); static int dollar(int quoted); @@ -571,20 +527,17 @@ static int grave(int quoted); static void globname(char *we, char *pp); static char *generate(char *start1, char *end1, char *middle, char *end); static int anyspcl(struct wdblock *wb); -static int xstrcmp(char *p1, char *p2); -static void glob0(char *a0, unsigned a1, int a2, - int (*a3) (char *, char *)); static void readhere(char **name, char *s, int ec); static int xxchar(struct ioarg *ap); struct here { char *h_tag; - int h_dosub; + char h_dosub; struct ioword *h_iop; struct here *h_next; }; -static const char * const signame[] = { +static const char *const signame[] = { "Signal 0", "Hangup", NULL, /* interrupt */ @@ -600,42 +553,17 @@ static const char * const signame[] = { "SIGUSR2", NULL, /* broken pipe */ "Alarm clock", - "Terminated", + "Terminated" }; -#define NSIGNAL (sizeof(signame)/sizeof(signame[0])) -struct res { - const char *r_name; - int r_val; -}; -static const struct res restab[] = { - { "for" , FOR }, - { "case" , CASE }, - { "esac" , ESAC }, - { "while", WHILE }, - { "do" , DO }, - { "done" , DONE }, - { "if" , IF }, - { "in" , IN }, - { "then" , THEN }, - { "else" , ELSE }, - { "elif" , ELIF }, - { "until", UNTIL }, - { "fi" , FI }, - { ";;" , BREAK }, - { "||" , LOGOR }, - { "&&" , LOGAND }, - { "{" , '{' }, - { "}" , '}' }, - { "." , DOT }, - { NULL , 0 }, -}; +typedef int (*builtin_func_ptr)(struct op *, char **); struct builtincmd { const char *name; - int (*builtinfunc)(struct op *t); + builtin_func_ptr builtinfunc; }; + static const struct builtincmd builtincmds[] = { { "." , dodot }, { ":" , dolabel }, @@ -660,23 +588,22 @@ static const struct builtincmd builtincmds[] = { { NULL , NULL }, }; -static struct op *scantree(struct op *); -static struct op *dowholefile(int, int); +static struct op *dowholefile(int /*, int*/); /* Globals */ static char **dolv; static int dolc; static int exstat; -static char gflg; -static int interactive; /* Is this an interactive shell */ -static int execflg; -static int multiline; /* \n changed to ; */ -static struct op *outtree; /* result from parser */ +static smallint gflg; /* (seems to be a parse error indicator) */ +static smallint interactive; /* Is this an interactive shell */ +static smallint execflg; +static smallint isbreak; /* "break" statement was seen */ +static int multiline; /* '\n' changed to ';' (counter) */ +static struct op *outtree; /* result from parser */ static xint *failpt; static xint *errpt; static struct brkcon *brklist; -static int isbreak; static struct wdblock *wdlist; static struct wdblock *iolist; @@ -692,11 +619,11 @@ static struct var *shell; /* shell to interpret command files */ static struct var *ifs; /* field separators */ static int areanum; /* current allocation area */ -static int intr; /* interrupt pending */ +static smallint intr; /* interrupt pending (bool) */ +static smallint heedint = 1; /* heed interrupt signals (bool) */ static int inparse; static char *null = (char*)""; /* null value for variable */ -static int heedint = 1; /* heed interrupt signals */ -static void (*qflag) (int) = SIG_IGN; +static void (*qflag)(int) = SIG_IGN; static int startl; static int peeksym; static int nlseen; @@ -712,6 +639,10 @@ static struct region *areanxt; /* starting point of scan */ static void *brktop; static void *brkaddr; +#define AFID_NOBUF (~0) +#define AFID_ID 0 + + /* * parsing & execution environment */ @@ -724,50 +655,70 @@ struct env { struct env *oenv; }; -static struct env e = { - NULL /* set to line in main() */, /* linep: char ptr */ - iostack, /* iobase: struct io ptr */ - iostack - 1, /* iop: struct io ptr */ - (xint *) NULL, /* errpt: void ptr for errors? */ - FDBASE, /* iofd: file desc */ - (struct env *) NULL /* oenv: struct env ptr */ -}; - struct globals { + struct env global_env; + struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */ + unsigned bufid; // = AFID_ID; /* buffer id counter */ char ourtrap[_NSIG + 1]; char *trap[_NSIG + 1]; struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */ struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */ struct ioarg ioargstack[NPUSH]; + /* + * flags: + * -e: quit on error + * -k: look for name=value everywhere on command line + * -n: no execution + * -t: exit after reading and executing one command + * -v: echo as read + * -x: trace + * -u: unset variables net diagnostic + */ + char flags['z' - 'a' + 1]; char filechar_cmdbuf[BUFSIZ]; char line[LINELIM]; char child_cmd[LINELIM]; + + struct io iostack[NPUSH]; + + char grave__var_name[LINELIM]; + char grave__alt_value[LINELIM]; }; #define G (*ptr_to_globals) +#define global_env (G.global_env ) +#define temparg (G.temparg ) +#define bufid (G.bufid ) #define ourtrap (G.ourtrap ) #define trap (G.trap ) #define sharedbuf (G.sharedbuf ) #define mainbuf (G.mainbuf ) #define ioargstack (G.ioargstack ) +/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */ +#define FLAG (G.flags - 'a' ) #define filechar_cmdbuf (G.filechar_cmdbuf) #define line (G.line ) #define child_cmd (G.child_cmd ) +#define iostack (G.iostack ) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + global_env.linep = line; \ + global_env.iobase = iostack; \ + global_env.iop = iostack - 1; \ + global_env.iofd = FDBASE; \ + temparg.afid = AFID_NOBUF; \ + bufid = AFID_ID; \ +} while (0) -#ifdef MSHDEBUG -void print_t(struct op *t) -{ - DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t, - T_CMD_NAMES[t->type], t->words, t->ioact)); +/* in substitution */ +#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL) - if (t->words) { - DBGPRINTF(("T: W1: %s", t->words[0])); - } -} +#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen))) -void print_tree(struct op *head) +#ifdef MSHDEBUG +static void print_tree(struct op *head) { if (head == NULL) { DBGPRINTF(("PRINT_TREE: no tree\n")); @@ -858,21 +809,21 @@ static void warn(const char *s) exstat = -1; } prs("\n"); - if (flag['e']) + if (FLAG['e']) leave(); } static void err(const char *s) { warn(s); - if (flag['n']) + if (FLAG['n']) return; if (!interactive) leave(); - if (e.errpt) - longjmp(e.errpt, 1); + if (global_env.errpt) + longjmp(global_env.errpt, 1); closeall(); - e.iop = e.iobase = iostack; + global_env.iop = global_env.iobase = iostack; } @@ -1037,7 +988,7 @@ static void garbage(void) #endif } -static char *space(int n) +static void *get_space(int n) { char *cp; @@ -1051,7 +1002,7 @@ static char *strsave(const char *s, int a) { char *cp; - cp = space(strlen(s) + 1); + cp = get_space(strlen(s) + 1); if (cp == NULL) { // FIXME: I highly doubt this is good. return (char*)""; @@ -1109,8 +1060,8 @@ static struct var *lookup(const char *n) return vp; cp = findeq(n); - vp = (struct var *) space(sizeof(*vp)); - if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { + vp = get_space(sizeof(*vp)); + if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) { dummy.name = dummy.value = (char*)""; return &dummy; } @@ -1145,13 +1096,13 @@ static void nameval(struct var *vp, const char *val, const char *name) if (vp->status & RONLY) { xp = vp->name; while (*xp && *xp != '=') - putc(*xp++, stderr); + fputc(*xp++, stderr); err(" is read-only"); return; } fl = 0; if (name == NULL) { - xp = space(strlen(vp->name) + strlen(val) + 2); + xp = get_space(strlen(vp->name) + strlen(val) + 2); if (xp == NULL) return; /* make string: name=value */ @@ -1298,7 +1249,7 @@ static void setdash(void) cp = m; for (c = 'a'; c <= 'z'; c++) - if (flag[c]) + if (FLAG[c]) *cp++ = c; *cp = '\0'; setval(lookup("-"), m); @@ -1313,7 +1264,7 @@ static int newfile(char *s) f = 0; if (NOT_LONE_DASH(s)) { DBGPRINTF(("NEWFILE: s is %s\n", s)); - f = open(s, 0); + f = open(s, O_RDONLY); if (f < 0) { prs(s); err(": cannot open"); @@ -1326,6 +1277,7 @@ static int newfile(char *s) } +#ifdef UNUSED struct op *scantree(struct op *head) { struct op *dotnode; @@ -1345,18 +1297,19 @@ struct op *scantree(struct op *head) return dotnode; } - if (head->words == NULL) + if (head->op_words == NULL) return NULL; DBGPRINTF5(("SCANTREE: checking node %p\n", head)); - if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) { + if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) { DBGPRINTF5(("SCANTREE: dot found in node %p\n", head)); return head; } return NULL; } +#endif static void onecommand(void) @@ -1366,17 +1319,17 @@ static void onecommand(void) DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree)); - while (e.oenv) + while (global_env.oenv) quitenv(); areanum = 1; freehere(areanum); freearea(areanum); garbage(); - wdlist = 0; - iolist = 0; - e.errpt = 0; - e.linep = line; + wdlist = NULL; + iolist = NULL; + global_env.errpt = NULL; + global_env.linep = line; yynerrs = 0; multiline = 0; inparse = 1; @@ -1389,7 +1342,7 @@ static void onecommand(void) if (setjmp(failpt) || yyparse() || intr) { DBGPRINTF(("ONECOMMAND: this is not good.\n")); - while (e.oenv) + while (global_env.oenv) quitenv(); scraphere(); if (!interactive && intr) @@ -1404,10 +1357,10 @@ static void onecommand(void) intr = 0; execflg = 0; - if (!flag['n']) { + if (!FLAG['n']) { DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n", outtree)); - execute(outtree, NOPIPE, NOPIPE, 0); + execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0); } if (!interactive && intr) { @@ -1433,15 +1386,15 @@ static int newenv(int f) return 1; } - ep = (struct env *) space(sizeof(*ep)); + ep = get_space(sizeof(*ep)); if (ep == NULL) { - while (e.oenv) + while (global_env.oenv) quitenv(); fail(); } - *ep = e; - e.oenv = ep; - e.errpt = errpt; + *ep = global_env; + global_env.oenv = ep; + global_env.errpt = errpt; return 0; } @@ -1451,15 +1404,15 @@ static void quitenv(void) struct env *ep; int fd; - DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv)); + DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv)); - ep = e.oenv; + ep = global_env.oenv; if (ep != NULL) { - fd = e.iofd; - e = *ep; + fd = global_env.iofd; + global_env = *ep; /* should close `'d files */ DELETE(ep); - while (--fd >= e.iofd) + while (--fd >= global_env.iofd) close(fd); } } @@ -1496,7 +1449,7 @@ static void next(int f) PUSHIO(afile, f, filechar); } -static void onintr(int s) /* ANSI C requires a parameter */ +static void onintr(int s ATTRIBUTE_UNUSED) /* ANSI C requires a parameter */ { signal(SIGINT, onintr); intr = 1; @@ -1594,10 +1547,11 @@ static int gmatch(const char *s, const char *p) static void yyerror(const char *s) ATTRIBUTE_NORETURN; static void yyerror(const char *s) { - yynerrs++; - if (interactive && e.iop <= iostack) { + yynerrs = 1; + if (interactive && global_env.iop <= iostack) { multiline = 0; - while (eofc() == 0 && yylex(0) != '\n'); + while (eofc() == 0 && yylex(0) != '\n') + continue; } err(s); fail(); @@ -1618,7 +1572,7 @@ int yyparse(void) yynerrs = 0; outtree = c_list(); musthave('\n', 0); - return (yynerrs != 0); + return yynerrs; /* 0/1 */ } static struct op *pipeline(int cf) @@ -1640,7 +1594,7 @@ static struct op *pipeline(int cf) zzerr(); } - if (t->type != TPAREN && t->type != TCOM) { + if (t->op_type != TPAREN && t->op_type != TCOM) { /* shell statement */ t = block(TPAREN, t, NOBLOCK, NOWORDS); } @@ -1674,7 +1628,7 @@ static struct op *andor(void) } t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS); - } /* WHILE */ + } peeksym = c; } @@ -1698,8 +1652,8 @@ static struct op *c_list(void) t = block(TASYNC, t, NOBLOCK, NOWORDS); while ((c = yylex(0)) == ';' || c == '&' - || (multiline && c == '\n')) { - + || (multiline && c == '\n') + ) { p = andor(); if (p== NULL) return t; @@ -1770,7 +1724,7 @@ static struct op *simple(void) case WORD: if (t == NULL) { t = newtp(); - t->type = TCOM; + t->op_type = TCOM; } peeksym = 0; word(yylval.cp); @@ -1822,7 +1776,7 @@ static struct op *command(int cf) if (iolist == NULL) return NULL; t = newtp(); - t->type = TCOM; + t->op_type = TCOM; } break; @@ -1836,12 +1790,12 @@ static struct op *command(int cf) case FOR: t = newtp(); - t->type = TFOR; + t->op_type = TFOR; musthave(WORD, 0); startl = 1; t->str = yylval.cp; multiline++; - t->words = wordlist(); + t->op_words = wordlist(); c = yylex(0); if (c != '\n' && c != ';') peeksym = c; @@ -1853,16 +1807,16 @@ static struct op *command(int cf) case UNTIL: multiline++; t = newtp(); - t->type = c == WHILE ? TWHILE : TUNTIL; + t->op_type = (c == WHILE ? TWHILE : TUNTIL); t->left = c_list(); t->right = dogroup(1); - t->words = NULL; + /* t->op_words = NULL; - newtp() did this */ multiline--; break; case CASE: t = newtp(); - t->type = TCASE; + t->op_type = TCASE; musthave(WORD, 0); t->str = yylval.cp; startl++; @@ -1879,7 +1833,7 @@ static struct op *command(int cf) case IF: multiline++; t = newtp(); - t->type = TIF; + t->op_type = TIF; t->left = c_list(); t->right = thenpart(); musthave(FI, 0); @@ -1888,19 +1842,20 @@ static struct op *command(int cf) case DOT: t = newtp(); - t->type = TDOT; + t->op_type = TDOT; - musthave(WORD, 0); /* gets name of file */ + musthave(WORD, 0); /* gets name of file */ DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp)); - word(yylval.cp); /* add word to wdlist */ - word(NOWORD); /* terminate wdlist */ - t->words = copyw(); /* dup wdlist */ + word(yylval.cp); /* add word to wdlist */ + word(NOWORD); /* terminate wdlist */ + t->op_words = copyw(); /* dup wdlist */ break; } - while (synio(0)); + while (synio(0)) + continue; t = namelist(t); iolist = iosave; @@ -1910,11 +1865,11 @@ static struct op *command(int cf) return t; } -static struct op *dowholefile(int type, int mark) +static struct op *dowholefile(int type /*, int mark*/) { struct op *t; - DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark)); + DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/)); multiline++; t = c_list(); @@ -1950,7 +1905,7 @@ static struct op *thenpart(void) return NULL; } t = newtp(); - t->type = 0; + /*t->op_type = 0; - newtp() did this */ t->left = c_list(); if (t->left == NULL) zzerr(); @@ -1972,7 +1927,7 @@ static struct op *elsepart(void) case ELIF: t = newtp(); - t->type = TELIF; + t->op_type = TELIF; t->left = c_list(); t->right = thenpart(); return t; @@ -2004,8 +1959,8 @@ static struct op *casepart(void) DBGPRINTF7(("CASEPART: enter...\n")); t = newtp(); - t->type = TPAT; - t->words = pattern(); + t->op_type = TPAT; + t->op_words = pattern(); musthave(')', 0); t->left = c_list(); peeksym = yylex(CONTIN); @@ -2073,13 +2028,12 @@ static struct op *block(int type, struct op *t1, struct op *t2, char **wp) DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type])); t = newtp(); - t->type = type; + t->op_type = type; t->left = t1; t->right = t2; - t->words = wp; + t->op_words = wp; - DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, - t2)); + DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2)); return t; } @@ -2087,11 +2041,38 @@ static struct op *block(int type, struct op *t1, struct op *t2, char **wp) /* See if given string is a shell multiline (FOR, IF, etc) */ static int rlookup(char *n) { + struct res { + char r_name[6]; + int16_t r_val; + }; + static const struct res restab[] = { + { "for" , FOR }, + { "case" , CASE }, + { "esac" , ESAC }, + { "while", WHILE }, + { "do" , DO }, + { "done" , DONE }, + { "if" , IF }, + { "in" , IN }, + { "then" , THEN }, + { "else" , ELSE }, + { "elif" , ELIF }, + { "until", UNTIL }, + { "fi" , FI }, + { ";;" , BREAK }, + { "||" , LOGOR }, + { "&&" , LOGAND }, + { "{" , '{' }, + { "}" , '}' }, + { "." , DOT }, + { }, + }; + const struct res *rp; DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n)); - for (rp = restab; rp->r_name; rp++) + for (rp = restab; rp->r_name[0]; rp++) if (strcmp(rp->r_name, n) == 0) { DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val)); return rp->r_val; /* Return numeric code for shell multiline */ @@ -2106,12 +2087,7 @@ static struct op *newtp(void) struct op *t; t = (struct op *) tree(sizeof(*t)); - t->type = 0; - t->words = NULL; - t->ioact = NULL; - t->left = NULL; - t->right = NULL; - t->str = NULL; + memset(t, 0, sizeof(*t)); DBGPRINTF3(("NEWTP: allocated %p\n", t)); @@ -2120,9 +2096,8 @@ static struct op *newtp(void) static struct op *namelist(struct op *t) { - DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t, - T_CMD_NAMES[t->type], iolist)); + T_CMD_NAMES[t->op_type], iolist)); if (iolist) { iolist = addword((char *) NULL, iolist); @@ -2130,8 +2105,8 @@ static struct op *namelist(struct op *t) } else t->ioact = NULL; - if (t->type != TCOM) { - if (t->type != TPAREN && t->ioact != NULL) { + if (t->op_type != TCOM) { + if (t->op_type != TPAREN && t->ioact != NULL) { t = block(TPAREN, t, NOBLOCK, NOWORDS); t->ioact = t->left->ioact; t->left->ioact = NULL; @@ -2140,7 +2115,7 @@ static struct op *namelist(struct op *t) } word(NOWORD); - t->words = copyw(); + t->op_words = copyw(); return t; } @@ -2150,7 +2125,7 @@ static char **copyw(void) char **wd; wd = getwords(wdlist); - wdlist = 0; + wdlist = NULL; return wd; } @@ -2164,7 +2139,7 @@ static struct ioword **copyio(void) struct ioword **iop; iop = (struct ioword **) getwords(iolist); - iolist = 0; + iolist = NULL; return iop; } @@ -2173,7 +2148,7 @@ static struct ioword *io(int u, int f, char *cp) struct ioword *iop; iop = (struct ioword *) tree(sizeof(*iop)); - iop->io_unit = u; + iop->io_fd = u; iop->io_flag = f; iop->io_name = cp; iolist = addword((char *) iop, iolist); @@ -2197,14 +2172,14 @@ static int yylex(int cf) atstart = startl; startl = 0; yylval.i = 0; - e.linep = line; + global_env.linep = line; /* MALAMO */ line[LINELIM - 1] = '\0'; loop: while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */ - ; + continue; switch (c) { default: @@ -2215,13 +2190,14 @@ static int yylex(int cf) iounit = c - '0'; goto loop; } - *e.linep++ = c; + *global_env.linep++ = c; c = c1; } break; - case '#': /* Comment, skip to next newline or End-of-string */ - while ((c = my_getc(0)) != '\0' && c != '\n'); + case '#': /* Comment, skip to next newline or End-of-string */ + while ((c = my_getc(0)) != '\0' && c != '\n') + continue; unget(c); goto loop; @@ -2231,7 +2207,7 @@ static int yylex(int cf) case '$': DBGPRINTF9(("YYLEX: found $\n")); - *e.linep++ = c; + *global_env.linep++ = c; c = my_getc(0); if (c == '{') { c = collect(c, '}'); @@ -2272,7 +2248,7 @@ static int yylex(int cf) gethere(); startl = 1; if (multiline || cf & CONTIN) { - if (interactive && e.iop <= iostack) { + if (interactive && global_env.iop <= iostack) { #if ENABLE_FEATURE_EDITING current_prompt = cprompt->value; #else @@ -2294,10 +2270,10 @@ static int yylex(int cf) pack: while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) { - if (e.linep >= elinep) + if (global_env.linep >= elinep) err("word too long"); else - *e.linep++ = c; + *global_env.linep++ = c; }; unget(c); @@ -2305,7 +2281,7 @@ static int yylex(int cf) if (any(c, "\"'`$")) goto loop; - *e.linep++ = '\0'; + *global_env.linep++ = '\0'; if (atstart) { c = rlookup(line); @@ -2326,7 +2302,7 @@ static int collect(int c, int c1) DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1)); - *e.linep++ = c; + *global_env.linep++ = c; while ((c = my_getc(c1)) != c1) { if (c == 0) { unget(c); @@ -2336,17 +2312,17 @@ static int collect(int c, int c1) yyerror(s); return YYERRCODE; } - if (interactive && c == '\n' && e.iop <= iostack) { + if (interactive && c == '\n' && global_env.iop <= iostack) { #if ENABLE_FEATURE_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); #endif } - *e.linep++ = c; + *global_env.linep++ = c; } - *e.linep++ = c; + *global_env.linep++ = c; DBGPRINTF8(("COLLECT: return 0, line is %s\n", line)); @@ -2425,10 +2401,10 @@ static struct op **find1case(struct op *t, const char *w) return NULL; } - DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type, - T_CMD_NAMES[t->type])); + DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type, + T_CMD_NAMES[t->op_type])); - if (t->type == TLIST) { + if (t->op_type == TLIST) { tp = find1case(t->left, w); if (tp != NULL) { DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp)); @@ -2438,7 +2414,7 @@ static struct op **find1case(struct op *t, const char *w) } else t1 = t; - for (wp = t1->words; *wp;) { + for (wp = t1->op_words; *wp;) { cp = evalstr(*wp++, DOSUB); if (cp && gmatch(w, cp)) { DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n", @@ -2463,7 +2439,7 @@ static struct op *findcase(struct op *t, const char *w) * execute tree */ -static int execute(struct op *t, int *pin, int *pout, int act) +static int execute(struct op *t, int *pin, int *pout, int no_fork) { struct op *t1; volatile int i, rv, a; @@ -2483,41 +2459,42 @@ static int execute(struct op *t, int *pin, int *pout, int act) return 0; } - DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t, - t->type, T_CMD_NAMES[t->type], - ((t->words == NULL) ? "NULL" : t->words[0]))); + DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t, + t->op_type, T_CMD_NAMES[t->op_type], + ((t->op_words == NULL) ? "NULL" : t->op_words[0]))); rv = 0; a = areanum++; - wp = (wp2 = t->words) != NULL - ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) + wp2 = t->op_words; + wp = (wp2 != NULL) + ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY) : NULL; - switch (t->type) { + switch (t->op_type) { case TDOT: DBGPRINTF3(("EXECUTE: TDOT\n")); outtree_save = outtree; - newfile(evalstr(t->words[0], DOALL)); + newfile(evalstr(t->op_words[0], DOALL)); - t->left = dowholefile(TLIST, 0); + t->left = dowholefile(TLIST /*, 0*/); t->right = NULL; outtree = outtree_save; if (t->left) - rv = execute(t->left, pin, pout, 0); + rv = execute(t->left, pin, pout, /* no_fork: */ 0); if (t->right) - rv = execute(t->right, pin, pout, 0); + rv = execute(t->right, pin, pout, /* no_fork: */ 0); break; case TPAREN: - rv = execute(t->left, pin, pout, 0); + rv = execute(t->left, pin, pout, /* no_fork: */ 0); break; case TCOM: - rv = forkexec(t, pin, pout, act, wp); + rv = forkexec(t, pin, pout, no_fork, wp); break; case TPIPE: @@ -2529,19 +2506,19 @@ static int execute(struct op *t, int *pin, int *pout, int act) break; pv[0] = remap(pv[0]); pv[1] = remap(pv[1]); - (void) execute(t->left, pin, pv, 0); - rv = execute(t->right, pv, pout, 0); + (void) execute(t->left, pin, pv, /* no_fork: */ 0); + rv = execute(t->right, pv, pout, /* no_fork: */ 0); } break; case TLIST: - (void) execute(t->left, pin, pout, 0); - rv = execute(t->right, pin, pout, 0); + (void) execute(t->left, pin, pout, /* no_fork: */ 0); + rv = execute(t->right, pin, pout, /* no_fork: */ 0); break; case TASYNC: { - int hinteractive = interactive; + smallint hinteractive = interactive; DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n")); @@ -2554,15 +2531,14 @@ static int execute(struct op *t, int *pin, int *pout, int act) interactive = 0; if (pin == NULL) { close(0); - open(bb_dev_null, 0); + xopen(bb_dev_null, O_RDONLY); } - _exit(execute(t->left, pin, pout, FEXEC)); + _exit(execute(t->left, pin, pout, /* no_fork: */ 1)); } interactive = hinteractive; if (i != -1) { setval(lookup("!"), putn(i)); - if (pin != NULL) - closepipe(pin); + closepipe(pin); if (interactive) { prs(putn(i)); prs("\n"); @@ -2575,10 +2551,10 @@ static int execute(struct op *t, int *pin, int *pout, int act) case TOR: case TAND: - rv = execute(t->left, pin, pout, 0); + rv = execute(t->left, pin, pout, /* no_fork: */ 0); t1 = t->right; - if (t1 != NULL && (rv == 0) == (t->type == TAND)) - rv = execute(t1, pin, pout, 0); + if (t1 != NULL && (rv == 0) == (t->op_type == TAND)) + rv = execute(t1, pin, pout, /* no_fork: */ 0); break; case TFOR: @@ -2589,7 +2565,8 @@ static int execute(struct op *t, int *pin, int *pout, int act) i = 0; } else { i = -1; - while (*wp++ != NULL); + while (*wp++ != NULL) + continue; } vp = lookup(t->str); while (setjmp(bc.brkpt)) @@ -2598,7 +2575,7 @@ static int execute(struct op *t, int *pin, int *pout, int act) brkset(&bc); for (t1 = t->left; i-- && *wp != NULL;) { setval(vp, *wp++); - rv = execute(t1, pin, pout, 0); + rv = execute(t1, pin, pout, /* no_fork: */ 0); } brklist = brklist->nextlev; break; @@ -2610,17 +2587,17 @@ static int execute(struct op *t, int *pin, int *pout, int act) goto broken; brkset(&bc); t1 = t->left; - while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) - rv = execute(t->right, pin, pout, 0); + while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE)) + rv = execute(t->right, pin, pout, /* no_fork: */ 0); brklist = brklist->nextlev; break; case TIF: case TELIF: if (t->right != NULL) { - rv = !execute(t->left, pin, pout, 0) ? - execute(t->right->left, pin, pout, 0) : - execute(t->right->right, pin, pout, 0); + rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ? + execute(t->right->left, pin, pout, /* no_fork: */ 0) : + execute(t->right->right, pin, pout, /* no_fork: */ 0); } break; @@ -2636,7 +2613,7 @@ static int execute(struct op *t, int *pin, int *pout, int act) t1 = findcase(t->left, cp); if (t1 != NULL) { DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1)); - rv = execute(t1, pin, pout, 0); + rv = execute(t1, pin, pout, /* no_fork: */ 0); DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1)); } break; @@ -2654,15 +2631,17 @@ static int execute(struct op *t, int *pin, int *pout, int act) if (rv >= 0) { t1 = t->left; if (t1) { - rv = execute(t1, pin, pout, 0); + rv = execute(t1, pin, pout, /* no_fork: */ 0); } } break; }; - broken: - t->words = wp2; + broken: +// Restoring op_words is most likely not needed now: see comment in forkexec() +// (also take a look at exec builtin (doexec) - it touches t->op_words) + t->op_words = wp2; isbreak = 0; freehere(areanum); freearea(areanum); @@ -2682,88 +2661,95 @@ static int execute(struct op *t, int *pin, int *pout, int act) return rv; } -typedef int (*builtin_func_ptr)(struct op *); - -static builtin_func_ptr inbuilt(const char *s) { +static builtin_func_ptr inbuilt(const char *s) +{ const struct builtincmd *bp; for (bp = builtincmds; bp->name; bp++) if (strcmp(bp->name, s) == 0) return bp->builtinfunc; - return NULL; } -static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) +static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp) { pid_t newpid; - int i, rv; - builtin_func_ptr shcom = NULL; - int f; - const char *cp = NULL; + int i; + builtin_func_ptr bltin = NULL; + const char *bltin_name = NULL; + const char *cp; struct ioword **iopp; int resetsig; char **owp; - int forked = 0; + int forked; int *hpin = pin; int *hpout = pout; char *hwp; - int hinteractive; - int hintr; + smallint hinteractive; + smallint hintr; + smallint hexecflg; struct brkcon *hbrklist; - int hexecflg; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &pin; (void) &pout; (void) ℘ - (void) &shcom; + (void) &bltin; (void) &cp; (void) &resetsig; (void) &owp; #endif - DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin, - pout, act)); - DBGPRINTF7(("FORKEXEC: t->words is %s\n", - ((t->words == NULL) ? "NULL" : t->words[0]))); - + DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin, + pout, no_fork)); + DBGPRINTF7(("FORKEXEC: t->op_words is %s\n", + ((t->op_words == NULL) ? "NULL" : t->op_words[0]))); owp = wp; resetsig = 0; - rv = -1; /* system-detected error */ - if (t->type == TCOM) { - while (*wp++ != NULL); + if (t->op_type == TCOM) { + while (*wp++ != NULL) + continue; cp = *wp; /* strip all initial assignments */ - /* not correct wrt PATH=yyy command etc */ - if (flag['x']) { + /* FIXME: not correct wrt PATH=yyy command etc */ + if (FLAG['x']) { DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n", cp, wp, owp)); echo(cp ? wp : owp); } - if (cp == NULL && t->ioact == NULL) { - while ((cp = *owp++) != NULL && assign(cp, COPYV)) - /**/; - DBGPRINTF(("FORKEXEC: returning setstatus()\n")); - return setstatus(0); - } - if (cp != NULL) { - shcom = inbuilt(cp); + if (cp == NULL) { + if (t->ioact == NULL) { + while ((cp = *owp++) != NULL && assign(cp, COPYV)) + continue; + DBGPRINTF(("FORKEXEC: returning setstatus(0)\n")); + return setstatus(0); + } + } else { /* cp != NULL */ + bltin_name = cp; + bltin = inbuilt(cp); } } - t->words = wp; - f = act; - - DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom, - f & FEXEC, owp)); - - if (shcom == NULL && (f & FEXEC) == 0) { - /* Save values in case the child process alters them */ + forked = 0; + // We were pointing t->op_words to temporary (expanded) arg list: + // t->op_words = wp; + // and restored it later (in execute()), but "break" + // longjmps away (at "Run builtin" below), leaving t->op_words clobbered! + // See http://bugs.busybox.net/view.php?id=846. + // Now we do not touch t->op_words, but separately pass wp as param list + // to builtins + DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin, + no_fork, owp)); + /* Don't fork if it is a lone builtin (not in pipe) + * OR we are told to _not_ fork */ + if ((!bltin || pin || pout) /* not lone bltin AND */ + && !no_fork /* not told to avoid fork */ + ) { + /* Save values in case child alters them after vfork */ hpin = pin; hpout = pout; hwp = *wp; @@ -2773,9 +2759,7 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) hexecflg = execflg; DBGPRINTF3(("FORKEXEC: calling vfork()...\n")); - newpid = vfork(); - if (newpid == -1) { DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n")); return -1; @@ -2790,19 +2774,13 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) intr = hintr; brklist = hbrklist; execflg = hexecflg; -/* moved up - if (i == -1) - return rv; -*/ - if (pin != NULL) - closepipe(pin); + closepipe(pin); return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0); } - /* Must be the child process, pid should be 0 */ - DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom)); - + /* Child */ + DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name)); if (interactive) { signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); @@ -2815,48 +2793,51 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) execflg = 0; } - if (owp != NULL) + if (owp) while ((cp = *owp++) != NULL && assign(cp, COPYV)) - if (shcom == NULL) + if (!bltin) export(lookup(cp)); -#ifdef COMPIPE - if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { - err("piping to/from shell builtins not yet done"); - if (forked) - _exit(-1); - return -1; - } -#endif - - if (pin != NULL) { - dup2(pin[0], 0); - closepipe(pin); + if (pin) { /* NB: close _first_, then move fds! */ + close(pin[1]); + xmove_fd(pin[0], 0); } - if (pout != NULL) { - dup2(pout[1], 1); - closepipe(pout); + if (pout) { + close(pout[0]); + xmove_fd(pout[1], 1); } iopp = t->ioact; - if (iopp != NULL) { - if (shcom != NULL && shcom != doexec) { - prs(cp); + if (iopp) { + if (bltin && bltin != doexec) { + prs(bltin_name); err(": cannot redirect shell command"); if (forked) _exit(-1); return -1; } - while (*iopp) + while (*iopp) { if (iosetup(*iopp++, pin != NULL, pout != NULL)) { + /* system-detected error */ if (forked) - _exit(rv); - return rv; + _exit(-1); + return -1; } + } } - if (shcom) { - i = setstatus((*shcom) (t)); + if (bltin) { + if (forked || pin || pout) { + /* Builtin in pipe: disallowed */ + /* TODO: allow "exec"? */ + prs(bltin_name); + err(": cannot run builtin as part of pipe"); + if (forked) + _exit(-1); + return -1; + } + /* Run builtin */ + i = setstatus(bltin(t, wp)); if (forked) _exit(i); DBGPRINTF(("FORKEXEC: returning i=%d\n", i)); @@ -2871,8 +2852,8 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) signal(SIGQUIT, SIG_DFL); } - if (t->type == TPAREN) - _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); + if (t->op_type == TPAREN) + _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1)); if (wp[0] == NULL) _exit(0); @@ -2883,11 +2864,11 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) if (!execflg) trap[0] = NULL; - DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid)); + DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid())); leave(); /* NOTREACHED */ - _exit(1); + return 0; } /* @@ -2903,13 +2884,13 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout) DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop, pipein, pipeout)); - if (iop->io_unit == IODEFAULT) /* take default */ - iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1; + if (iop->io_fd == IODEFAULT) /* take default */ + iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1; - if (pipein && iop->io_unit == 0) + if (pipein && iop->io_fd == 0) return 0; - if (pipeout && iop->io_unit == 1) + if (pipeout && iop->io_fd == 1) return 0; msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create"; @@ -2930,9 +2911,10 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout) iop->io_flag = IOCLOSE; iop->io_flag &= ~(IOREAD | IOWRITE); } + switch (iop->io_flag) { case IOREAD: - u = open(cp, 0); + u = open(cp, O_RDONLY); break; case IOHERE: @@ -2942,33 +2924,33 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout) break; case IOWRITE | IOCAT: - u = open(cp, 1); + u = open(cp, O_WRONLY); if (u >= 0) { lseek(u, (long) 0, SEEK_END); break; } + /* fall through to creation if >>file doesn't exist */ + case IOWRITE: u = creat(cp, 0666); break; case IODUP: - u = dup2(*cp - '0', iop->io_unit); + u = dup2(*cp - '0', iop->io_fd); break; case IOCLOSE: - close(iop->io_unit); + close(iop->io_fd); return 0; } + if (u < 0) { prs(cp); prs(": cannot "); warn(msg); return 1; } - if (u != iop->io_unit) { - dup2(u, iop->io_unit); - close(u); - } + xmove_fd(u, iop->io_fd); return 0; } @@ -2992,7 +2974,7 @@ static int waitfor(int lastpid, int canintr) { int pid, rv; int s; - int oheedint = heedint; + smallint oheedint = heedint; heedint = 0; rv = 0; @@ -3004,7 +2986,7 @@ static int waitfor(int lastpid, int canintr) } else { rv = WAITSIG(s); if (rv != 0) { - if (rv < NSIGNAL) { + if (rv < ARRAY_SIZE(signame)) { if (signame[rv] != NULL) { if (pid != lastpid) { prn(pid); @@ -3023,9 +3005,9 @@ static int waitfor(int lastpid, int canintr) } if (WAITCORE(s)) prs(" - core dumped"); - if (rv >= NSIGNAL || signame[rv]) + if (rv >= ARRAY_SIZE(signame) || signame[rv]) prs("\n"); - rv = -1; + rv |= 0x80; } else rv = WAITVAL(s); } @@ -3058,19 +3040,17 @@ static int setstatus(int s) */ static const char *rexecve(char *c, char **v, char **envp) { - int i; const char *sp; char *tp; - int eacces = 0, asis = 0; + int asis = 0; char *name = c; if (ENABLE_FEATURE_SH_STANDALONE) { - optind = 1; - if (find_applet_by_name(name)) { + if (find_applet_by_name(name) >= 0) { /* We have to exec here since we vforked. Running * run_applet_and_exit() won't work and bad things * will happen. */ - execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp); + execve(bb_busybox_exec_path, v, envp); } } @@ -3080,7 +3060,7 @@ static const char *rexecve(char *c, char **v, char **envp) asis = (*sp == '\0'); while (asis || *sp != '\0') { asis = 0; - tp = e.linep; + tp = global_env.linep; for (; *sp != '\0'; tp++) { *tp = *sp++; if (*tp == ':') { @@ -3088,32 +3068,31 @@ static const char *rexecve(char *c, char **v, char **envp) break; } } - if (tp != e.linep) + if (tp != global_env.linep) *tp++ = '/'; - for (i = 0; (*tp++ = c[i++]) != '\0';); + strcpy(tp, c); + //for (i = 0; (*tp++ = c[i++]) != '\0';) + // continue; - DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep)); + DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep)); - execve(e.linep, v, envp); + execve(global_env.linep, v, envp); switch (errno) { case ENOEXEC: - *v = e.linep; - tp = *--v; - *v = e.linep; + *v = global_env.linep; + v--; + tp = *v; + *v = global_env.linep; execve(DEFAULT_SHELL, v, envp); *v = tp; - return "no Shell"; + return "no shell"; case ENOMEM: return (char *) bb_msg_memory_exhausted; case E2BIG: return "argument list too long"; - - case EACCES: - eacces++; - break; } } return errno == ENOENT ? "not found" : "cannot execute"; @@ -3149,14 +3128,14 @@ static int run(struct ioarg *argp, int (*f) (struct ioarg *)) errpt = ev; if (newenv(setjmp(errpt)) == 0) { - wdlist = 0; - iolist = 0; + wdlist = NULL; + iolist = NULL; pushio(argp, f); - e.iobase = e.iop; + global_env.iobase = global_env.iop; yynerrs = 0; failpt = rt; if (setjmp(failpt) == 0 && yyparse() == 0) - rv = execute(outtree, NOPIPE, NOPIPE, 0); + rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0); quitenv(); } else { DBGPRINTF(("RUN: error from newenv()!\n")); @@ -3177,7 +3156,7 @@ static int run(struct ioarg *argp, int (*f) (struct ioarg *)) * built-in commands: doX */ -static int dohelp(struct op *t) +static int dohelp(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED) { int col; const struct builtincmd *x; @@ -3190,22 +3169,22 @@ static int dohelp(struct op *t) while (x->name) { col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name); if (col > 60) { - puts(""); + bb_putchar('\n'); col = 0; } x++; } #if ENABLE_FEATURE_SH_STANDALONE { - const struct bb_applet *applet = applets; + const char *applet = applet_names; - while (applet->name) { - col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name); + while (*applet) { + col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet); if (col > 60) { - puts(""); + bb_putchar('\n'); col = 0; } - applet++; + applet += strlen(applet) + 1; } } #endif @@ -3213,16 +3192,16 @@ static int dohelp(struct op *t) return EXIT_SUCCESS; } -static int dolabel(struct op *t) +static int dolabel(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED) { return 0; } -static int dochdir(struct op *t) +static int dochdir(struct op *t ATTRIBUTE_UNUSED, char **args) { const char *cp, *er; - cp = t->words[1]; + cp = args[1]; if (cp == NULL) { cp = homedir->value; if (cp != NULL) @@ -3239,11 +3218,11 @@ static int dochdir(struct op *t) return 1; } -static int doshift(struct op *t) +static int doshift(struct op *t ATTRIBUTE_UNUSED, char **args) { int n; - n = t->words[1] ? getn(t->words[1]) : 1; + n = args[1] ? getn(args[1]) : 1; if (dolc < n) { err("nothing to shift"); return 1; @@ -3258,7 +3237,7 @@ static int doshift(struct op *t) /* * execute login and newgrp directly */ -static int dologin(struct op *t) +static int dologin(struct op *t ATTRIBUTE_UNUSED, char **args) { const char *cp; @@ -3266,55 +3245,64 @@ static int dologin(struct op *t) signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); } - cp = rexecve(t->words[0], t->words, makenv(0, NULL)); - prs(t->words[0]); + cp = rexecve(args[0], args, makenv(0, NULL)); + prs(args[0]); prs(": "); err(cp); return 1; } -static int doumask(struct op *t) +static int doumask(struct op *t ATTRIBUTE_UNUSED, char **args) { - int i, n; + int i; char *cp; - cp = t->words[1]; + cp = args[1]; if (cp == NULL) { i = umask(0); umask(i); - for (n = 3 * 4; (n -= 3) >= 0;) - putc('0' + ((i >> n) & 07), stderr); - putc('\n', stderr); + printf("%04o\n", i); } else { -/* huh??? '8','9' are not allowed! */ - for (n = 0; *cp >= '0' && *cp <= '9'; cp++) - n = n * 8 + (*cp - '0'); - umask(n); + i = bb_strtou(cp, NULL, 8); + if (errno) { + err("umask: bad octal number"); + return 1; + } + umask(i); } return 0; } -static int doexec(struct op *t) +static int doexec(struct op *t, char **args) { - int i; jmp_buf ex; xint *ofail; + char **sv_words; t->ioact = NULL; - for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++); - if (i == 0) + if (!args[1]) return 1; + execflg = 1; ofail = failpt; failpt = ex; + + sv_words = t->op_words; + t->op_words = args + 1; +// TODO: test what will happen with "exec break" - +// will it leave t->op_words pointing to garbage? +// (see http://bugs.busybox.net/view.php?id=846) if (setjmp(failpt) == 0) - execute(t, NOPIPE, NOPIPE, FEXEC); + execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1); + t->op_words = sv_words; + failpt = ofail; execflg = 0; + return 1; } -static int dodot(struct op *t) +static int dodot(struct op *t ATTRIBUTE_UNUSED, char **args) { int i; const char *sp; @@ -3322,9 +3310,10 @@ static int dodot(struct op *t) char *cp; int maltmp; - 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))); + DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n", + t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep))); - cp = t->words[1]; + cp = args[1]; if (cp == NULL) { DBGPRINTF(("DODOT: bad args, ret 0\n")); return 0; @@ -3333,25 +3322,25 @@ static int dodot(struct op *t) sp = any('/', cp) ? ":" : path->value; - DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n", + DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n", ((sp == NULL) ? "NULL" : sp), - ((e.linep == NULL) ? "NULL" : e.linep))); + ((global_env.linep == NULL) ? "NULL" : global_env.linep))); while (*sp) { - tp = e.linep; + tp = global_env.linep; while (*sp && (*tp = *sp++) != ':') tp++; - if (tp != e.linep) + if (tp != global_env.linep) *tp++ = '/'; - - for (i = 0; (*tp++ = cp[i++]) != '\0';); + strcpy(tp, cp); /* Original code */ - i = open(e.linep, 0); + i = open(global_env.linep, O_RDONLY); if (i >= 0) { exstat = 0; maltmp = remap(i); - DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep)); + DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n", + maltmp, exstat, global_env.iofd, i, global_env.linep)); next(maltmp); /* Basically a PUSHIO */ @@ -3367,12 +3356,12 @@ static int dodot(struct op *t) return -1; } -static int dowait(struct op *t) +static int dowait(struct op *t ATTRIBUTE_UNUSED, char **args) { int i; char *cp; - cp = t->words[1]; + cp = args[1]; if (cp != NULL) { i = getn(cp); if (i == 0) @@ -3383,19 +3372,19 @@ static int dowait(struct op *t) return 0; } -static int doread(struct op *t) +static int doread(struct op *t ATTRIBUTE_UNUSED, char **args) { char *cp, **wp; int nb = 0; int nl = 0; - if (t->words[1] == NULL) { + if (args[1] == NULL) { err("Usage: read name ..."); return 1; } - for (wp = t->words + 1; *wp; wp++) { - for (cp = e.linep; !nl && cp < elinep - 1; cp++) { - nb = read(0, cp, sizeof(*cp)); + for (wp = args + 1; *wp; wp++) { + for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) { + nb = nonblock_safe_read(0, cp, sizeof(*cp)); if (nb != sizeof(*cp)) break; nl = (*cp == '\n'); @@ -3405,22 +3394,22 @@ static int doread(struct op *t) *cp = '\0'; if (nb <= 0) break; - setval(lookup(*wp), e.linep); + setval(lookup(*wp), global_env.linep); } return nb <= 0; } -static int doeval(struct op *t) +static int doeval(struct op *t ATTRIBUTE_UNUSED, char **args) { - return RUN(awordlist, t->words + 1, wdchar); + return RUN(awordlist, args + 1, wdchar); } -static int dotrap(struct op *t) +static int dotrap(struct op *t ATTRIBUTE_UNUSED, char **args) { int n, i; int resetsig; - if (t->words[1] == NULL) { + if (args[1] == NULL) { for (i = 0; i <= _NSIG; i++) if (trap[i]) { prn(i); @@ -3430,14 +3419,14 @@ static int dotrap(struct op *t) } return 0; } - resetsig = isdigit(*t->words[1]); - for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { - n = getsig(t->words[i]); + resetsig = isdigit(args[1][0]); + for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) { + n = getsig(args[i]); freecell(trap[n]); trap[n] = 0; if (!resetsig) { - if (*t->words[1] != '\0') { - trap[n] = strsave(t->words[1], 0); + if (args[1][0] != '\0') { + trap[n] = strsave(args[1], 0); setsig(n, sig); } else setsig(n, SIG_IGN); @@ -3496,14 +3485,14 @@ static int getn(char *as) return n * m; } -static int dobreak(struct op *t) +static int dobreak(struct op *t ATTRIBUTE_UNUSED, char **args) { - return brkcontin(t->words[1], 1); + return brkcontin(args[1], 1); } -static int docontinue(struct op *t) +static int docontinue(struct op *t ATTRIBUTE_UNUSED, char **args) { - return brkcontin(t->words[1], 0); + return brkcontin(args[1], 0); } static int brkcontin(char *cp, int val) @@ -3524,17 +3513,17 @@ static int brkcontin(char *cp, int val) err("bad break/continue level"); return 1; } - isbreak = val; + isbreak = (val != 0); longjmp(bc->brkpt, 1); /* NOTREACHED */ } -static int doexit(struct op *t) +static int doexit(struct op *t ATTRIBUTE_UNUSED, char **args) { char *cp; execflg = 0; - cp = t->words[1]; + cp = args[1]; if (cp != NULL) setstatus(getn(cp)); @@ -3545,15 +3534,15 @@ static int doexit(struct op *t) return 0; } -static int doexport(struct op *t) +static int doexport(struct op *t ATTRIBUTE_UNUSED, char **args) { - rdexp(t->words + 1, export, EXPORT); + rdexp(args + 1, export, EXPORT); return 0; } -static int doreadonly(struct op *t) +static int doreadonly(struct op *t ATTRIBUTE_UNUSED, char **args) { - rdexp(t->words + 1, ronly, RONLY); + rdexp(args + 1, ronly, RONLY); return 0; } @@ -3568,7 +3557,8 @@ static void rdexp(char **wp, void (*f) (struct var *), int key) char *cp; assign(*wp, COPYV); - for (cp = *wp; *cp != '='; cp++); + for (cp = *wp; *cp != '='; cp++) + continue; *cp = '\0'; } if (checkname(*wp)) @@ -3586,46 +3576,45 @@ static void badid(char *s) err(": bad identifier"); } -static int doset(struct op *t) +static int doset(struct op *t ATTRIBUTE_UNUSED, char **args) { struct var *vp; char *cp; int n; - cp = t->words[1]; + cp = args[1]; if (cp == NULL) { for (vp = vlist; vp; vp = vp->next) varput(vp->name, 1); return 0; } if (*cp == '-') { - /* bad: t->words++; */ - for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++); + args++; if (*++cp == 0) - flag['x'] = flag['v'] = 0; + FLAG['x'] = FLAG['v'] = 0; else { for (; *cp; cp++) { switch (*cp) { case 'e': if (!interactive) - flag['e']++; + FLAG['e']++; break; default: if (*cp >= 'a' && *cp <= 'z') - flag[(int) *cp]++; + FLAG[(int) *cp]++; break; } } } setdash(); } - if (t->words[1]) { - t->words[0] = dolv[0]; - for (n = 1; t->words[n]; n++) - setarea((char *) t->words[n], 0); + if (args[1]) { + args[0] = dolv[0]; + for (n = 1; args[n]; n++) + setarea((char *) args[n], 0); dolc = n - 1; - dolv = t->words; + dolv = args; setval(lookup("#"), putn(dolc)); setarea((char *) (dolv - 1), 0); } @@ -3645,21 +3634,40 @@ static void varput(char *s, int out) * Copyright (c) 1999 Herbert Xu * This file contains code for the times builtin. */ -static int dotimes(struct op *t) +static void times_fmt(char *buf, clock_t val, unsigned clk_tck) +{ + unsigned min, sec; + if (sizeof(val) > sizeof(int)) + sec = ((unsigned long)val) / clk_tck; + else + sec = ((unsigned)val) / clk_tck; + min = sec / 60; +#if ENABLE_DESKTOP + sprintf(buf, "%um%u.%03us", min, (sec - min * 60), + /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck + ); +#else + sprintf(buf, "%um%us", min, (sec - min * 60)); +#endif +} + +static int dotimes(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED) { struct tms buf; - long clk_tck = sysconf(_SC_CLK_TCK); + unsigned clk_tck = sysconf(_SC_CLK_TCK); + /* How much do we need for "NmN.NNNs" ? */ + enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 }; + char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE]; + char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE]; times(&buf); - printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", - (int) (buf.tms_utime / clk_tck / 60), - ((double) buf.tms_utime) / clk_tck, - (int) (buf.tms_stime / clk_tck / 60), - ((double) buf.tms_stime) / clk_tck, - (int) (buf.tms_cutime / clk_tck / 60), - ((double) buf.tms_cutime) / clk_tck, - (int) (buf.tms_cstime / clk_tck / 60), - ((double) buf.tms_cstime) / clk_tck); + + times_fmt(u, buf.tms_utime, clk_tck); + times_fmt(s, buf.tms_stime, clk_tck); + times_fmt(cu, buf.tms_cutime, clk_tck); + times_fmt(cs, buf.tms_cstime, clk_tck); + + printf("%s %s\n%s %s\n", u, s, cu, cs); return 0; } @@ -3696,14 +3704,14 @@ static char **eval(char **ap, int f) if (newenv(setjmp(errpt)) == 0) { while (*ap && isassign(*ap)) expand(*ap++, &wb, f & ~DOGLOB); - if (flag['k']) { + if (FLAG['k']) { for (wf = ap; *wf; wf++) { if (isassign(*wf)) expand(*wf, &wb, f & ~DOGLOB); } } - for (wb = addword((char *) 0, wb); *ap; ap++) { - if (!flag['k'] || !isassign(*ap)) + for (wb = addword((char *) NULL, wb); *ap; ap++) { + if (!FLAG['k'] || !isassign(*ap)) expand(*ap, &wb, f & ~DOKEY); } wb = addword((char *) 0, wb); @@ -3763,9 +3771,9 @@ static int expand(const char *cp, struct wdblock **wbp, int f) errpt = ev; if (newenv(setjmp(errpt)) == 0) { PUSHIO(aword, cp, strchar); - e.iobase = e.iop; + global_env.iobase = global_env.iop; while ((xp = blank(f)) && gflg == 0) { - e.linep = xp; + global_env.linep = xp; xp = strsave(xp, areanum); if ((f & DOGLOB) == 0) { if (f & DOTRIM) @@ -3814,7 +3822,7 @@ static char *blank(int f) DBGPRINTF3(("BLANK: enter, f=%d\n", f)); - sp = e.linep; + sp = global_env.linep; scanequals = f & DOKEY; foundequals = 0; @@ -3822,9 +3830,9 @@ static char *blank(int f) c = subgetc('"', foundequals); switch (c) { case 0: - if (sp == e.linep) + if (sp == global_env.linep) return 0; - *e.linep++ = 0; + *global_env.linep++ = 0; return sp; default: @@ -3842,7 +3850,7 @@ static char *blank(int f) break; if (c == '\'' || !any(c, "$`\"")) c |= QUOTE; - *e.linep++ = c; + *global_env.linep++ = c; } c = 0; } @@ -3867,9 +3875,9 @@ static char *blank(int f) } else if (!isalnum(c) && c != '_') scanequals = 0; } - *e.linep++ = c; + *global_env.linep++ = c; } - *e.linep++ = 0; + *global_env.linep++ = 0; return sp; } @@ -3888,13 +3896,13 @@ static int subgetc(char ec, int quoted) if (c == '`') { if (grave(quoted) == 0) return 0; - e.iop->task = XGRAVE; + global_env.iop->task = XGRAVE; goto again; } if (c == '$') { c = dollar(quoted); if (c == 0) { - e.iop->task = XDOLL; + global_env.iop->task = XDOLL; goto again; } } @@ -3916,38 +3924,38 @@ static int dollar(int quoted) DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted)); c = readc(); - s = e.linep; + s = global_env.linep; if (c != '{') { - *e.linep++ = c; + *global_env.linep++ = c; if (isalpha(c) || c == '_') { while ((c = readc()) != 0 && (isalnum(c) || c == '_')) - if (e.linep < elinep) - *e.linep++ = c; + if (global_env.linep < elinep) + *global_env.linep++ = c; unget(c); } c = 0; } else { - oiop = e.iop; - otask = e.iop->task; + oiop = global_env.iop; + otask = global_env.iop->task; - e.iop->task = XOTHER; + global_env.iop->task = XOTHER; while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n') - if (e.linep < elinep) - *e.linep++ = c; - if (oiop == e.iop) - e.iop->task = otask; + if (global_env.linep < elinep) + *global_env.linep++ = c; + if (oiop == global_env.iop) + global_env.iop->task = otask; if (c != '}') { err("unclosed ${"); - gflg++; + gflg = 1; return c; } } - if (e.linep >= elinep) { + if (global_env.linep >= elinep) { err("string in ${} too long"); - gflg++; - e.linep -= 10; + gflg = 1; + global_env.linep -= 10; } - *e.linep = 0; + *global_env.linep = 0; if (*s) for (cp = s + 1; *cp; cp++) if (any(*cp, "=-+?")) { @@ -3959,7 +3967,7 @@ static int dollar(int quoted) if (dolc > 1) { /* currently this does not distinguish $* and $@ */ /* should check dollar */ - e.linep = s; + global_env.linep = s; PUSHIO(awordlist, dolv + 1, dolchar); return 0; } else { /* trap the nasty ${=} */ @@ -3974,7 +3982,7 @@ static int dollar(int quoted) case '=': if (isdigit(*s)) { err("cannot use ${...=...} with $n"); - gflg++; + gflg = 1; break; } setval(vp, cp); @@ -3991,17 +3999,17 @@ static int dollar(int quoted) err(s); } else err(cp); - gflg++; + gflg = 1; break; } } else if (c == '+') dolp = strsave(cp, areanum); - if (flag['u'] && dolp == null) { + if (FLAG['u'] && dolp == null) { prs("unset variable: "); err(s); - gflg++; + gflg = 1; } - e.linep = s; + global_env.linep = s; PUSHIO(aword, dolp, quoted ? qstrchar : strchar); return 0; } @@ -4031,7 +4039,7 @@ static int grave(int quoted) (void) &cp; #endif - for (cp = e.iop->argp->aword; *cp != '`'; cp++) { + for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) { if (*cp == 0) { err("no closing `"); return 0; @@ -4039,7 +4047,7 @@ static int grave(int quoted) } /* string copy with dollar expansion */ - src = e.iop->argp->aword; + src = global_env.iop->argp->aword; dest = child_cmd; count = 0; ignore = 0; @@ -4051,8 +4059,12 @@ static int grave(int quoted) ignore_once = 1; if (*src == '$' && !ignore && !ignore_once) { struct var *vp; + /* moved to G to reduce stack usage char var_name[LINELIM]; char alt_value[LINELIM]; + */ +#define var_name (G.grave__var_name) +#define alt_value (G.grave__alt_value) int var_index = 0; int alt_index = 0; char operator = 0; @@ -4140,6 +4152,8 @@ static int grave(int quoted) count++; } } +#undef var_name +#undef alt_value } else { *dest++ = *src++; count++; @@ -4151,7 +4165,8 @@ static int grave(int quoted) if (openpipe(pf) < 0) return 0; - while ((i = vfork()) == -1 && errno == EAGAIN); + while ((i = vfork()) == -1 && errno == EAGAIN) + continue; DBGPRINTF3(("GRAVE: i is %p\n", io)); @@ -4161,8 +4176,8 @@ static int grave(int quoted) return 0; } if (i != 0) { - waitpid(i, NULL, 0); - e.iop->argp->aword = ++cp; + waitpid(i, NULL, 0); // safe_waitpid? + global_env.iop->argp->aword = ++cp; close(pf[1]); PUSHIO(afile, remap(pf[0]), (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar)); @@ -4174,8 +4189,14 @@ static int grave(int quoted) if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN) signal(j, SIG_DFL); - dup2(pf[1], 1); - closepipe(pf); + /* Testcase where below checks are needed: + * close stdout & run this script: + * files=`ls` + * echo "$files" >zz + */ + xmove_fd(pf[1], 1); + if (pf[0] != 1) + close(pf[0]); argument_list[0] = (char *) DEFAULT_SHELL; argument_list[1] = (char *) "-c"; @@ -4212,7 +4233,7 @@ static char *unquote(char *as) #define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent)) static struct wdblock *cl, *nl; -static char spcl[] = "[?*"; +static const char spcl[] ALIGN1= "[?*"; static struct wdblock *glob(char *cp, struct wdblock *wb) { @@ -4243,10 +4264,10 @@ static struct wdblock *glob(char *cp, struct wdblock *wb) DELETE(cl->w_words[i]); DELETE(cl); } - for (i = 0; i < cl->w_nword; i++) - unquote(cl->w_words[i]); - glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); if (cl->w_nword) { + for (i = 0; i < cl->w_nword; i++) + unquote(cl->w_words[i]); + qsort_string_vector(cl->w_words, cl->w_nword); for (i = 0; i < cl->w_nword; i++) wb = addword(cl->w_words[i], wb); DELETE(cl); @@ -4270,11 +4291,13 @@ static void globname(char *we, char *pp) for (np = we; np != pp; pp--) if (pp[-1] == '/') break; - for (dp = cp = space((int) (pp - np) + 3); np < pp;) + dp = cp = get_space((int) (pp - np) + 3); + while (np < pp) *cp++ = *np++; *cp++ = '.'; *cp = '\0'; - for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';) + gp = cp = get_space(strlen(pp) + 1); + while (*np && *np != '/') *cp++ = *np++; *cp = '\0'; dirp = opendir(dp); @@ -4323,12 +4346,14 @@ static char *generate(char *start1, char *end1, char *middle, char *end) char *p; char *op, *xp; - p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2); - for (xp = start1; xp != end1;) + p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2); + xp = start1; + while (xp != end1) *op++ = *xp++; - for (xp = middle; (*op++ = *xp++) != '\0';); - op--; - for (xp = end; (*op++ = *xp++) != '\0';); + xp = middle; + while (*xp != '\0') + *op++ = *xp++; + strcpy(op, end); return p; } @@ -4344,11 +4369,6 @@ static int anyspcl(struct wdblock *wb) return 0; } -static int xstrcmp(char *p1, char *p2) -{ - return strcmp(*(char **) p1, *(char **) p2); -} - /* -------- word.c -------- */ @@ -4356,7 +4376,7 @@ static struct wdblock *newword(int nw) { struct wdblock *wb; - wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *)); + wb = get_space(sizeof(*wb) + nw * sizeof(char *)); wb->w_bsize = nw; wb->w_nword = 0; return wb; @@ -4382,8 +4402,7 @@ static struct wdblock *addword(char *wd, struct wdblock *wb) return wb; } -static -char **getwords(struct wdblock *wb) +static char **getwords(struct wdblock *wb) { char **wd; int nb; @@ -4394,129 +4413,13 @@ char **getwords(struct wdblock *wb) DELETE(wb); return NULL; } - wd = (char **) space(nb = sizeof(*wd) * wb->w_nword); - memcpy((char *) wd, (char *) wb->w_words, nb); - DELETE(wb); /* perhaps should done by caller */ + nb = sizeof(*wd) * wb->w_nword; + wd = get_space(nb); + memcpy(wd, wb->w_words, nb); + DELETE(wb); /* perhaps should done by caller */ return wd; } -static int (*func) (char *, char *); -static int globv; - -static void glob3(char *i, char *j, char *k) -{ - char *index1, *index2, *index3; - int c; - int m; - - m = globv; - index1 = i; - index2 = j; - index3 = k; - do { - c = *index1; - *index1++ = *index3; - *index3++ = *index2; - *index2++ = c; - } while (--m); -} - -static void glob2(char *i, char *j) -{ - char *index1, *index2, c; - int m; - - m = globv; - index1 = i; - index2 = j; - do { - c = *index1; - *index1++ = *index2; - *index2++ = c; - } while (--m); -} - -static void glob1(char *base, char *lim) -{ - char *i, *j; - int v2; - char *lptr, *hptr; - int c; - unsigned n; - - v2 = globv; - - top: - n = (int) (lim - base); - if (n <= v2) - return; - n = v2 * (n / (2 * v2)); - hptr = lptr = base + n; - i = base; - j = lim - v2; - for (;;) { - if (i < lptr) { - c = (*func) (i, lptr); - if (c == 0) { - lptr -= v2; - glob2(i, lptr); - continue; - } - if (c < 0) { - i += v2; - continue; - } - } - - begin: - if (j > hptr) { - c = (*func) (hptr, j); - if (c == 0) { - hptr += v2; - glob2(hptr, j); - goto begin; - } - if (c > 0) { - if (i == lptr) { - hptr += v2; - glob3(i, hptr, j); - i = (lptr += v2); - goto begin; - } - glob2(i, j); - j -= v2; - i += v2; - continue; - } - j -= v2; - goto begin; - } - - - if (i == lptr) { - if (lptr - base >= lim - hptr) { - glob1(hptr + v2, lim); - lim = lptr; - } else { - glob1(base, lptr); - base = hptr + v2; - } - goto top; - } - - lptr -= v2; - glob3(j, lptr, i); - j = (hptr -= v2); - } -} - -static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *)) -{ - func = a3; - globv = a2; - glob1(a0, a0 + a1 * a2); -} - /* -------- io.c -------- */ @@ -4528,14 +4431,15 @@ static int my_getc(int ec) { int c; - if (e.linep > elinep) { - while ((c = readc()) != '\n' && c); + if (global_env.linep > elinep) { + while ((c = readc()) != '\n' && c) + continue; err("input line too long"); - gflg++; + gflg = 1; return c; } c = readc(); - if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) { + if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) { if (c == '\\') { c = readc(); if (c == '\n' && ec != '\"') @@ -4548,53 +4452,53 @@ static int my_getc(int ec) static void unget(int c) { - if (e.iop >= e.iobase) - e.iop->peekc = c; + if (global_env.iop >= global_env.iobase) + global_env.iop->peekc = c; } static int eofc(void) { - return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0); + return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0); } static int readc(void) { int c; - RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase)); + RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase)); - for (; e.iop >= e.iobase; e.iop--) { - RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc)); - c = e.iop->peekc; + for (; global_env.iop >= global_env.iobase; global_env.iop--) { + RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc)); + c = global_env.iop->peekc; if (c != '\0') { - e.iop->peekc = 0; + global_env.iop->peekc = 0; return c; } - if (e.iop->prev != 0) { - c = (*e.iop->iofn)(e.iop->argp, e.iop); + if (global_env.iop->prev != 0) { + c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop); if (c != '\0') { if (c == -1) { - e.iop++; + global_env.iop++; continue; } - if (e.iop == iostack) + if (global_env.iop == iostack) ioecho(c); - e.iop->prev = c; - return e.iop->prev; + global_env.iop->prev = c; + return c; } - if (e.iop->task == XIO && e.iop->prev != '\n') { - e.iop->prev = 0; - if (e.iop == iostack) + if (global_env.iop->task == XIO && global_env.iop->prev != '\n') { + global_env.iop->prev = 0; + if (global_env.iop == iostack) ioecho('\n'); return '\n'; } } - if (e.iop->task == XIO) { + if (global_env.iop->task == XIO) { if (multiline) { - e.iop->prev = 0; - return e.iop->prev; + global_env.iop->prev = 0; + return 0; } - if (interactive && e.iop == iostack + 1) { + if (interactive && global_env.iop == iostack + 1) { #if ENABLE_FEATURE_EDITING current_prompt = prompt->value; #else @@ -4604,94 +4508,92 @@ static int readc(void) } } /* FOR */ - if (e.iop >= iostack) { - RCPRINTF(("READC: return 0, e.iop %p\n", e.iop)); + if (global_env.iop >= iostack) { + RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop)); return 0; } DBGPRINTF(("READC: leave()...\n")); leave(); - /* NOTREACHED */ return 0; } static void ioecho(char c) { - if (flag['v']) + if (FLAG['v']) write(2, &c, sizeof c); } - static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *)) { - DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp, - argp->afid, e.iop)); + DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp, + argp->afid, global_env.iop)); /* Set env ptr for io source to next array spot and check for array overflow */ - if (++e.iop >= &iostack[NPUSH]) { - e.iop--; + if (++global_env.iop >= &iostack[NPUSH]) { + global_env.iop--; err("Shell input nested too deeply"); - gflg++; + gflg = 1; return; } /* We did not overflow the NPUSH array spots so setup data structs */ - e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */ + global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */ if (argp->afid != AFID_NOBUF) - e.iop->argp = argp; + global_env.iop->argp = argp; else { - e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */ - *e.iop->argp = *argp; /* copy data from temp area into stack spot */ + global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */ + *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */ /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */ - if (e.iop == &iostack[0]) - e.iop->argp->afbuf = &mainbuf; + if (global_env.iop == &iostack[0]) + global_env.iop->argp->afbuf = &mainbuf; else - e.iop->argp->afbuf = &sharedbuf; + global_env.iop->argp->afbuf = &sharedbuf; /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */ /* This line appears to be active when running scripts from command line */ - if ((isatty(e.iop->argp->afile) == 0) - && (e.iop == &iostack[0] - || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) { + if ((isatty(global_env.iop->argp->afile) == 0) + && (global_env.iop == &iostack[0] + || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) { if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */ bufid = AFID_ID; /* AFID_ID = 0 */ - e.iop->argp->afid = bufid; /* assign buffer id */ + global_env.iop->argp->afid = bufid; /* assign buffer id */ } - DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n", - iostack, e.iop, e.iop->argp->afbuf)); - DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n", - &mainbuf, &sharedbuf, bufid, e.iop)); + DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n", + iostack, global_env.iop, global_env.iop->argp->afbuf)); + DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n", + &mainbuf, &sharedbuf, bufid, global_env.iop)); } - e.iop->prev = ~'\n'; - e.iop->peekc = 0; - e.iop->xchar = 0; - e.iop->nlcount = 0; + global_env.iop->prev = ~'\n'; + global_env.iop->peekc = 0; + global_env.iop->xchar = 0; + global_env.iop->nlcount = 0; if (fn == filechar || fn == linechar) - e.iop->task = XIO; + global_env.iop->task = XIO; else if (fn == (int (*)(struct ioarg *)) gravechar - || fn == (int (*)(struct ioarg *)) qgravechar) - e.iop->task = XGRAVE; + || fn == (int (*)(struct ioarg *)) qgravechar) + global_env.iop->task = XGRAVE; else - e.iop->task = XOTHER; + global_env.iop->task = XOTHER; } static struct io *setbase(struct io *ip) { struct io *xp; - xp = e.iobase; - e.iobase = ip; + xp = global_env.iobase; + global_env.iobase = ip; return xp; } @@ -4700,16 +4602,16 @@ static struct io *setbase(struct io *ip) */ /* - * Produce the characters of a string, then a newline, then EOF. + * Produce the characters of a string, then a newline, then NUL. */ static int nlchar(struct ioarg *ap) { - int c; + char c; if (ap->aword == NULL) - return 0; + return '\0'; c = *ap->aword++; - if (c == 0) { + if (c == '\0') { ap->aword = NULL; return '\n'; } @@ -4809,7 +4711,7 @@ static int filechar(struct ioarg *ap) if (i) lseek(ap->afile, ap->afpos, SEEK_SET); - i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); + i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf)); if (i <= 0) { closef(ap->afile); return 0; @@ -4829,16 +4731,18 @@ static int filechar(struct ioarg *ap) static int position = 0, size = 0; while (size == 0 || position >= size) { - read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state); - size = strlen(filechar_cmdbuf); + size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state); + if (size < 0) /* Error/EOF */ + exit(0); position = 0; + /* if Ctrl-C, size == 0 and loop will repeat */ } c = filechar_cmdbuf[position]; position++; return c; } #endif - i = safe_read(ap->afile, &c, sizeof(c)); + i = nonblock_safe_read(ap->afile, &c, sizeof(c)); return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); } @@ -4849,7 +4753,7 @@ static int herechar(struct ioarg *ap) { char c; - if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { + if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) { close(ap->afile); c = '\0'; } @@ -4922,9 +4826,9 @@ static int remap(int fd) int map[NOFILE]; int newfd; - DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd)); + DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd)); - if (fd < e.iofd) { + if (fd < global_env.iofd) { for (i = 0; i < NOFILE; i++) map[i] = 0; @@ -4932,7 +4836,7 @@ static int remap(int fd) map[fd] = 1; newfd = dup(fd); fd = newfd; - } while (fd >= 0 && fd < e.iofd); + } while (fd >= 0 && fd < global_env.iofd); for (i = 0; i < NOFILE; i++) if (map[i]) @@ -4958,8 +4862,8 @@ static int openpipe(int *pv) static void closepipe(int *pv) { if (pv != NULL) { - close(*pv++); - close(*pv); + close(pv[0]); + close(pv[1]); } } @@ -4976,7 +4880,7 @@ static void markhere(char *s, struct ioword *iop) DBGPRINTF7(("MARKHERE: enter, s=%p\n", s)); - h = (struct here *) space(sizeof(struct here)); + h = get_space(sizeof(struct here)); if (h == NULL) return; @@ -5004,7 +4908,7 @@ static void markhere(char *s, struct ioword *iop) *s &= ~QUOTE; } } - h->h_dosub = iop->io_flag & IOXHERE; + h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\''); } static void gethere(void) @@ -5015,7 +4919,7 @@ static void gethere(void) /* Scan here files first leaving inhere list in place */ for (hp = h = inhere; h != NULL; hp = h, h = h->h_next) - readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\''); + readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */); /* Make inhere list active - keep list intact for scraphere */ if (hp != NULL) { @@ -5045,10 +4949,10 @@ static void readhere(char **name, char *s, int ec) if (newenv(setjmp(errpt)) != 0) unlink(tname); else { - pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn); - e.iobase = e.iop; + pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn); + global_env.iobase = global_env.iop; for (;;) { - if (interactive && e.iop <= iostack) { + if (interactive && global_env.iop <= iostack) { #if ENABLE_FEATURE_EDITING current_prompt = cprompt->value; #else @@ -5099,7 +5003,7 @@ static int herein(char *hname, int xdoll) DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll)); - hf = open(hname, 0); + hf = open(hname, O_RDONLY); if (hf < 0) return -1; @@ -5114,7 +5018,7 @@ static int herein(char *hname, int xdoll) errpt = ev; if (newenv(setjmp(errpt)) == 0) { PUSHIO(afile, hf, herechar); - setbase(e.iop); + setbase(global_env.iop); while ((c = subgetc(0, 0)) != 0) { c &= ~QUOTE; write(tf, &c, sizeof c); @@ -5123,7 +5027,7 @@ static int herein(char *hname, int xdoll) } else unlink(tname); close(tf); - tf = open(tname, 0); + tf = open(tname, O_RDONLY); unlink(tname); return tf; } @@ -5151,7 +5055,7 @@ static void freehere(int area) DBGPRINTF6(("FREEHERE: enter, area=%d\n", area)); hl = NULL; - for (h = acthere; h != NULL; h = h->h_next) + for (h = acthere; h != NULL; h = h->h_next) { if (getarea((char *) h) >= area) { if (h->h_iop->io_name != NULL) unlink(h->h_iop->io_name); @@ -5159,8 +5063,10 @@ static void freehere(int area) acthere = h->h_next; else hl->h_next = h->h_next; - } else + } else { hl = h; + } + } } @@ -5169,7 +5075,7 @@ static void freehere(int area) * shell */ -int msh_main(int argc, char **argv); +int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int msh_main(int argc, char **argv) { int f; @@ -5178,10 +5084,10 @@ int msh_main(int argc, char **argv) char *name, **ap; int (*iof) (struct ioarg *); - PTR_TO_GLOBALS = xzalloc(sizeof(G)); + INIT_G(); + sharedbuf.id = AFID_NOBUF; mainbuf.id = AFID_NOBUF; - e.linep = line; elinep = line + sizeof(line) - 5; #if ENABLE_FEATURE_EDITING @@ -5215,10 +5121,11 @@ int msh_main(int argc, char **argv) path = lookup("PATH"); if (path->value == null) { + /* Can be merged with same string elsewhere in bbox */ if (geteuid() == 0) - setval(path, "/sbin:/bin:/usr/sbin:/usr/bin"); + setval(path, bb_default_root_path); else - setval(path, "/bin:/usr/bin"); + setval(path, bb_default_path); } export(path); @@ -5279,10 +5186,10 @@ int msh_main(int argc, char **argv) break; case 'i': - interactive++; + interactive = 1; default: if (*s >= 'a' && *s <= 'z') - flag[(int) *s]++; + FLAG[(int) *s]++; } } else { argv--; @@ -5312,15 +5219,15 @@ int msh_main(int argc, char **argv) setdash(); /* This won't be true if PUSHIO has been called, say from newfile() above */ - if (e.iop < iostack) { + if (global_env.iop < iostack) { PUSHIO(afile, 0, iof); if (isatty(0) && isatty(1) && !cflag) { - interactive++; + interactive = 1; #if !ENABLE_FEATURE_SH_EXTRA_QUIET #ifdef MSHDEBUG - printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER); + printf("\n\n%s built-in shell (msh with debug)\n", bb_banner); #else - printf("\n\n%s Built-in shell (msh)\n", BB_BANNER); + printf("\n\n%s built-in shell (msh)\n", bb_banner); #endif printf("Enter 'help' for a list of built-in commands.\n\n"); #endif @@ -5329,11 +5236,11 @@ int msh_main(int argc, char **argv) signal(SIGQUIT, qflag); if (name && name[0] == '-') { - interactive++; - f = open(".profile", 0); + interactive = 1; + f = open(".profile", O_RDONLY); if (f >= 0) next(remap(f)); - f = open("/etc/profile", 0); + f = open("/etc/profile", O_RDONLY); if (f >= 0) next(remap(f)); } @@ -5342,25 +5249,28 @@ int msh_main(int argc, char **argv) if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); + +/* Handle "msh SCRIPT VAR=val params..." */ +/* Disabled: bash does not do it! */ +#if 0 + argv++; + /* skip leading args of the form VAR=val */ + while (*argv && assign(*argv, !COPYV)) { + argc--; + argv++; + } + argv--; +#endif dolv = argv; dolc = argc; dolv[0] = name; - if (dolc > 1) { - for (ap = ++argv; --argc > 0;) { - *ap = *argv++; - if (assign(*ap, !COPYV)) { - dolc--; /* keyword */ - } else { - ap++; - } - } - } + setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); - DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack)); + DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack)); for (;;) { - if (interactive && e.iop <= iostack) { + if (interactive && global_env.iop <= iostack) { #if ENABLE_FEATURE_EDITING current_prompt = prompt->value; #else