X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fmsh.c;h=ac49af14ceb6eaa68e084377eb050c7a775c00e4;hb=e0a336747c2061d0d555c4e15287b513831d2947;hp=d4f5345513ed79e54b218522360dd53138a553b8;hpb=0ee3999d13b662d233dfc7decdd4d691cd66fdda;p=oweals%2Fbusybox.git diff --git a/shell/msh.c b/shell/msh.c index d4f534551..ac49af14c 100644 --- a/shell/msh.c +++ b/shell/msh.c @@ -13,53 +13,121 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include "busybox.h" -#include #include +#include -#include "cmdedit.h" +#ifdef STANDALONE +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# 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 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 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) +{ + return NULL; +} +static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) +{ + unsigned i, out, res; + assert(sizeof(unsigned) == 4); + if (buflen) { + out = 0; + for (i = 1000000000; i; i /= 10) { + res = n / i; + if (res || out || i == 1) { + if (!--buflen) break; + out++; + n -= res*i; + *buf++ = '0' + res; + } + } + } + return buf; +} +static char *itoa_to_buf(int n, char *buf, unsigned buflen) +{ + if (buflen && n < 0) { + n = -n; + *buf++ = '-'; + buflen--; + } + return utoa_to_buf((unsigned)n, buf, buflen); +} +static char local_buf[12]; +static char *itoa(int n) +{ + *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; + return local_buf; +} +#else +# include "busybox.h" +extern char **environ; +#endif /*#define MSHDEBUG 1*/ #ifdef MSHDEBUG int mshdbg = MSHDEBUG; -#define DBGPRINTF(x) if(mshdbg>0)printf x -#define DBGPRINTF0(x) if(mshdbg>0)printf x -#define DBGPRINTF1(x) if(mshdbg>1)printf x -#define DBGPRINTF2(x) if(mshdbg>2)printf x -#define DBGPRINTF3(x) if(mshdbg>3)printf x -#define DBGPRINTF4(x) if(mshdbg>4)printf x -#define DBGPRINTF5(x) if(mshdbg>5)printf x -#define DBGPRINTF6(x) if(mshdbg>6)printf x -#define DBGPRINTF7(x) if(mshdbg>7)printf x -#define DBGPRINTF8(x) if(mshdbg>8)printf x -#define DBGPRINTF9(x) if(mshdbg>9)printf x +#define DBGPRINTF(x) if (mshdbg>0) printf x +#define DBGPRINTF0(x) if (mshdbg>0) printf x +#define DBGPRINTF1(x) if (mshdbg>1) printf x +#define DBGPRINTF2(x) if (mshdbg>2) printf x +#define DBGPRINTF3(x) if (mshdbg>3) printf x +#define DBGPRINTF4(x) if (mshdbg>4) printf x +#define DBGPRINTF5(x) if (mshdbg>5) printf x +#define DBGPRINTF6(x) if (mshdbg>6) printf x +#define DBGPRINTF7(x) if (mshdbg>7) printf x +#define DBGPRINTF8(x) if (mshdbg>8) printf x +#define DBGPRINTF9(x) if (mshdbg>9) printf x int mshdbg_rc = 0; -#define RCPRINTF(x) if(mshdbg_rc)printf x +#define RCPRINTF(x) if (mshdbg_rc) printf x #else #define DBGPRINTF(x) -#define DBGPRINTF0(x) -#define DBGPRINTF1(x) -#define DBGPRINTF2(x) -#define DBGPRINTF3(x) -#define DBGPRINTF4(x) -#define DBGPRINTF5(x) -#define DBGPRINTF6(x) -#define DBGPRINTF7(x) -#define DBGPRINTF8(x) -#define DBGPRINTF9(x) - -#define RCPRINTF(x) +#define DBGPRINTF0(x) ((void)0) +#define DBGPRINTF1(x) ((void)0) +#define DBGPRINTF2(x) ((void)0) +#define DBGPRINTF3(x) ((void)0) +#define DBGPRINTF4(x) ((void)0) +#define DBGPRINTF5(x) ((void)0) +#define DBGPRINTF6(x) ((void)0) +#define DBGPRINTF7(x) ((void)0) +#define DBGPRINTF8(x) ((void)0) +#define DBGPRINTF9(x) ((void)0) + +#define RCPRINTF(x) ((void)0) #endif /* MSHDEBUG */ -#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT +#if ENABLE_FEATURE_EDITING_FANCY_PROMPT # define DEFAULT_ROOT_PROMPT "\\u:\\w> " # define DEFAULT_USER_PROMPT "\\u:\\w$ " #else @@ -84,9 +152,9 @@ 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 @@ -96,14 +164,31 @@ typedef void xint; /* base type of jmp_buf, for not broken compilers */ /* * shell components */ - -#define QUOTE 0200 - #define NOBLOCK ((struct op *)NULL) #define NOWORD ((char *)NULL) #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 */ +}; + +#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 */ + + /* * Description of a command or an operation on commands. * Might eventually use a union. @@ -138,7 +223,7 @@ struct op { /* Strings for names to make debug easier */ #ifdef MSHDEBUG -static char *T_CMD_NAMES[] = { +static const char *const T_CMD_NAMES[] = { "PLACEHOLDER", "TCOM", "TPAREN", @@ -163,29 +248,20 @@ static char *T_CMD_NAMES[] = { /* * actions determining the environment of a process */ -#define BIT(i) (1<<(i)) -#define FEXEC BIT(0) /* execute without forking */ +#define FEXEC 1 /* 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); -static char *findeq(char *cp); -static char *cclass(char *p, int sub); -static void initarea(void); -extern int msh_main(int argc, char **argv); +#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) struct brkcon { @@ -194,39 +270,6 @@ struct brkcon { }; -/* - * redirection - */ -struct ioword { - short io_unit; /* unit affected */ - short io_flag; /* action (below) */ - 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 IODEFAULT (-1) /* token for default IO unit */ - - - -/* - * parsing & execution environment - */ -static struct env { - char *linep; - struct io *iobase; - struct io *iop; - xint *errpt; /* void * */ - int iofd; - struct env *oenv; -} e; - /* * flags: * -e: quit on error @@ -238,36 +281,30 @@ static struct env { * -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'; - -static char *null; /* null value for variable */ -static int intr; /* interrupt pending */ +/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */ +#define FLAG (flags - 'a') -static char *trap[_NSIG + 1]; -static char ourtrap[_NSIG + 1]; +/* moved to G: static char *trap[_NSIG + 1]; */ +/* moved to G: static char ourtrap[_NSIG + 1]; */ static int trapset; /* trap pending */ -static int heedint; /* heed interrupt signals */ - static int yynerrs; /* yacc */ -static char line[LINELIM]; -static char *elinep; +/* moved to G: static char line[LINELIM]; */ + +#if ENABLE_FEATURE_EDITING +static char *current_prompt; +static line_input_t *line_input_state; +#endif /* * other functions */ -static int (*inbuilt(char *s)) (struct op *); - -static char *rexecve(char *c, char **v, char **envp); -static char *space(int n); -static char *strsave(char *s, int a); +static const char *rexecve(char *c, char **v, char **envp); static char *evalstr(char *cp, int f); static char *putn(int n); static char *unquote(char *as); -static struct var *lookup(char *n); static int rlookup(char *n); static struct wdblock *glob(char *cp, struct wdblock *wb); static int my_getc(int ec); @@ -281,35 +318,21 @@ static void onintr(int s); /* SIGINT handler */ static int newenv(int f); static void quitenv(void); -static void err(char *s); -static int anys(char *s1, char *s2); -static int any(int c, char *s); static void next(int f); static void setdash(void); static void onecommand(void); static void runtrap(int i); -static int gmatch(char *s, char *p); - - -/* - * error handling - */ -static void leave(void); /* abort shell (or fail in subshell) */ -static void fail(void); /* fail but return to process next command */ -static void warn(char *s); -static void sig(int i); /* default signal handler */ - /* -------- 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 { @@ -318,7 +341,6 @@ struct region { }; - /* -------- grammar stuff -------- */ typedef union { char *cp; @@ -327,32 +349,30 @@ typedef union { struct op *o; } YYSTYPE; -#define WORD 256 -#define LOGAND 257 -#define LOGOR 258 -#define BREAK 259 -#define IF 260 -#define THEN 261 -#define ELSE 262 -#define ELIF 263 -#define FI 264 -#define CASE 265 -#define ESAC 266 -#define FOR 267 -#define WHILE 268 -#define UNTIL 269 -#define DO 270 -#define DONE 271 -#define IN 272 +#define WORD 256 +#define LOGAND 257 +#define LOGOR 258 +#define BREAK 259 +#define IF 260 +#define THEN 261 +#define ELSE 262 +#define ELIF 263 +#define FI 264 +#define CASE 265 +#define ESAC 266 +#define FOR 267 +#define WHILE 268 +#define UNTIL 269 +#define DO 270 +#define DONE 271 +#define IN 272 /* Added for "." file expansion */ -#define DOT 273 +#define DOT 273 #define YYERRCODE 300 /* flags to yylex */ -#define CONTIN 01 /* skip new lines to complete command */ - -#define SYNTAXERR zzerr() +#define CONTIN 01 /* skip new lines to complete command */ static struct op *pipeline(int cf); static struct op *andor(void); @@ -377,8 +397,6 @@ static char **copyw(void); static void word(char *cp); static struct ioword **copyio(void); static struct ioword *io(int u, int f, char *cp); -static void zzerr(void); -static void yyerror(char *s); static int yylex(int cf); static int collect(int c, int c1); static int dual(int c); @@ -400,63 +418,61 @@ struct var { #define GETCELL 04 /* name & value space was got with getcell */ static int yyparse(void); -static struct var *lookup(char *n); -static void setval(struct var *vp, char *val); -static void nameval(struct var *vp, char *val, char *name); -static void export(struct var *vp); -static void ronly(struct var *vp); -static int isassign(char *s); -static int checkname(char *cp); -static int assign(char *s, int cf); -static void putvlist(int f, int out); -static int eqname(char *n1, char *n2); static int execute(struct op *t, int *pin, int *pout, int act); +#define AFID_NOBUF (~0) +#define AFID_ID 0 + + /* -------- io.h -------- */ /* io buffer */ struct iobuf { - unsigned id; /* buffer id */ - char buf[512]; /* buffer */ - char *bufp; /* pointer into buffer */ - char *ebufp; /* pointer to end of buffer */ + unsigned id; /* buffer id */ + char buf[512]; /* buffer */ + char *bufp; /* pointer into buffer */ + char *ebufp; /* pointer to end of buffer */ }; /* possible arguments to an IO function */ struct ioarg { - char *aword; + const char *aword; char **awordlist; - int afile; /* file descriptor */ - unsigned afid; /* buffer id */ - long afpos; /* file position */ - struct iobuf *afbuf; /* buffer for this file */ + int afile; /* file descriptor */ + unsigned afid; /* buffer id */ + long afpos; /* file position */ + struct iobuf *afbuf; /* buffer for this file */ }; -//static struct ioarg ioargstack[NPUSH]; -#define AFID_NOBUF (~0) -#define AFID_ID 0 - /* an input generator's state */ struct io { int (*iofn) (struct ioarg *, struct io *); struct ioarg *argp; int peekc; - char prev; /* previous character read by readc() */ - char nlcount; /* for `'s */ - char xchar; /* for `'s */ - char task; /* reason for pushed IO */ + char prev; /* previous character read by readc() */ + char nlcount; /* for `'s */ + char xchar; /* for `'s */ + char task; /* reason for pushed IO */ }; -//static struct io iostack[NPUSH]; #define XOTHER 0 /* none of the below */ #define XDOLL 1 /* expanding ${} */ #define XGRAVE 2 /* expanding `'s */ -#define XIO 3 /* file IO */ +#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))) + /* * input generators for IO structure @@ -479,31 +495,22 @@ static int herein(char *hname, int xdoll); static int run(struct ioarg *argp, int (*f) (struct ioarg *)); -/* - * IO functions - */ static int eofc(void); static int readc(void); static void unget(int c); static void ioecho(char c); -static void prs(const char *s); -static void prn(unsigned u); -static void closef(int i); -static void closeall(void); /* * IO control */ static void pushio(struct ioarg *argp, int (*f) (struct ioarg *)); +#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen))) static int remap(int fd); static int openpipe(int *pv); static void closepipe(int *pv); static struct io *setbase(struct io *ip); -#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen))) -#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) - /* -------- word.h -------- */ #define NSTART 16 /* default number of words to allow for initially */ @@ -519,30 +526,10 @@ static struct wdblock *addword(char *wd, struct wdblock *wb); static struct wdblock *newword(int nw); static char **getwords(struct wdblock *wb); -/* -------- area.h -------- */ - -/* - * storage allocation - */ -static char *getcell(unsigned nbytes); -static void garbage(void); -static void setarea(char *cp, int a); -static int getarea(char *cp); -static void freearea(int a); -static void freecell(char *cp); -static int areanum; /* current allocation area */ - -#define NEW(type) (type *)getcell(sizeof(type)) -#define DELETE(obj) freecell((char *)obj) - - /* -------- misc stuff -------- */ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); static int iosetup(struct ioword *iop, int pipein, int pipeout); -static void echo(char **wp); -static struct op **find1case(struct op *t, char *w); -static struct op *findcase(struct op *t, char *w); static void brkset(struct brkcon *bc); static int dolabel(struct op *t); static int dohelp(struct op *t); @@ -570,7 +557,7 @@ 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(char *cp, struct wdblock **wbp, int f); +static int expand(const char *cp, struct wdblock **wbp, int f); static char *blank(int f); static int dollar(int quoted); static int grave(int quoted); @@ -578,13 +565,9 @@ 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 int a1, int a2, +static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *)); -static void glob1(char *base, char *lim); -static void glob2(char *i, char *j); -static void glob3(char *i, char *j, char *k); static void readhere(char **name, char *s, int ec); -static void pushio(struct ioarg *argp, int (*f) (struct ioarg *)); static int xxchar(struct ioarg *ap); struct here { @@ -597,7 +580,7 @@ struct here { static const char * const signame[] = { "Signal 0", "Hangup", - (char *) NULL, /* interrupt */ + NULL, /* interrupt */ "Quit", "Illegal instruction", "Trace/BPT trap", @@ -608,7 +591,7 @@ static const char * const signame[] = { "SIGUSR1", "SIGSEGV", "SIGUSR2", - (char *) NULL, /* broken pipe */ + NULL, /* broken pipe */ "Alarm clock", "Terminated", }; @@ -620,63 +603,61 @@ struct res { 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}, - {0, 0}, + { "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 }, }; - struct builtincmd { const char *name; - int (*builtinfunc) (struct op * t); + int (*builtinfunc)(struct op *t); }; static const struct builtincmd builtincmds[] = { - {".", dodot}, - {":", dolabel}, - {"break", dobreak}, - {"cd", dochdir}, - {"continue", docontinue}, - {"eval", doeval}, - {"exec", doexec}, - {"exit", doexit}, - {"export", doexport}, - {"help", dohelp}, - {"login", dologin}, - {"newgrp", dologin}, - {"read", doread}, - {"readonly", doreadonly}, - {"set", doset}, - {"shift", doshift}, - {"times", dotimes}, - {"trap", dotrap}, - {"umask", doumask}, - {"wait", dowait}, - {0, 0} + { "." , dodot }, + { ":" , dolabel }, + { "break" , dobreak }, + { "cd" , dochdir }, + { "continue", docontinue }, + { "eval" , doeval }, + { "exec" , doexec }, + { "exit" , doexit }, + { "export" , doexport }, + { "help" , dohelp }, + { "login" , dologin }, + { "newgrp" , dologin }, + { "read" , doread }, + { "readonly", doreadonly }, + { "set" , doset }, + { "shift" , doshift }, + { "times" , dotimes }, + { "trap" , dotrap }, + { "umask" , doumask }, + { "wait" , dowait }, + { NULL , NULL }, }; static struct op *scantree(struct op *); static struct op *dowholefile(int, int); -/* Globals */ -extern char **environ; /* environment pointer */ +/* Globals */ static char **dolv; static int dolc; static int exstat; @@ -691,11 +672,6 @@ static struct brkcon *brklist; static int isbreak; static struct wdblock *wdlist; static struct wdblock *iolist; -static char *trap[_NSIG + 1]; -static char ourtrap[_NSIG + 1]; -static int trapset; /* trap pending */ -static int yynerrs; /* yacc */ -static char line[LINELIM]; #ifdef MSHDEBUG static struct var *mshdbg_var; @@ -708,45 +684,72 @@ static struct var *path; /* search path for commands */ static struct var *shell; /* shell to interpret command files */ static struct var *ifs; /* field separators */ -static int areanum; /* current allocation area */ -static int intr; +static int areanum; /* current allocation area */ +static int intr; /* interrupt pending */ static int inparse; -static char *null = ""; -static int heedint = 1; -static void (*qflag) (int) = SIG_IGN; +static char *null = (char*)""; /* null value for variable */ +static int heedint = 1; /* heed interrupt signals */ +static void (*qflag)(int) = SIG_IGN; static int startl; static int peeksym; static int nlseen; static int iounit = IODEFAULT; static YYSTYPE yylval; -static char *elinep = line + sizeof(line) - 5; - -static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */ -static struct ioarg ioargstack[NPUSH]; -static struct io iostack[NPUSH]; -static struct iobuf sharedbuf = { AFID_NOBUF }; -static struct iobuf mainbuf = { AFID_NOBUF }; -static unsigned bufid = AFID_ID; /* buffer id counter */ +static char *elinep; /* done in main(): = line + sizeof(line) - 5 */ -static struct here *inhere; /* list of hear docs while parsing */ -static struct here *acthere; /* list of active here documents */ -static struct region *areabot; /* bottom of area */ -static struct region *areatop; /* top of area */ -static struct region *areanxt; /* starting point of scan */ +static struct here *inhere; /* list of hear docs while parsing */ +static struct here *acthere; /* list of active here documents */ +static struct region *areabot; /* bottom of area */ +static struct region *areatop; /* top of area */ +static struct region *areanxt; /* starting point of scan */ static void *brktop; static void *brkaddr; +/* + * parsing & execution environment + */ +struct env { + char *linep; + struct io *iobase; + struct io *iop; + xint *errpt; /* void * */ + int iofd; + struct env *oenv; +}; + static struct env e = { - line, /* 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 */ + 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 { + 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]; + char filechar_cmdbuf[BUFSIZ]; + char line[LINELIM]; + char child_cmd[LINELIM]; +}; + +#define G (*ptr_to_globals) +#define ourtrap (G.ourtrap ) +#define trap (G.trap ) +#define sharedbuf (G.sharedbuf ) +#define mainbuf (G.mainbuf ) +#define ioargstack (G.ioargstack ) +#define filechar_cmdbuf (G.filechar_cmdbuf) +#define line (G.line ) +#define child_cmd (G.child_cmd ) + + #ifdef MSHDEBUG -void print_t(struct op *t); void print_t(struct op *t) { DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t, @@ -755,11 +758,8 @@ void print_t(struct op *t) if (t->words) { DBGPRINTF(("T: W1: %s", t->words[0])); } - - return; } -void print_tree(struct op *head); void print_tree(struct op *head) { if (head == NULL) { @@ -775,212 +775,514 @@ void print_tree(struct op *head) if (head->right) print_tree(head->right); - - return; } -#endif /* MSHDEBUG */ +#endif /* MSHDEBUG */ -#ifdef CONFIG_FEATURE_COMMAND_EDITING -static char *current_prompt; -#endif - -/* -------- sh.c -------- */ /* - * shell + * IO functions */ +static void prs(const char *s) +{ + if (*s) + write(2, s, strlen(s)); +} - -int msh_main(int argc, char **argv) +static void prn(unsigned u) { - int f; - char *s; - int cflag; - char *name, **ap; - int (*iof) (struct ioarg *); + prs(itoa(u)); +} - DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); +static void echo(char **wp) +{ + int i; - initarea(); - if ((ap = environ) != NULL) { - while (*ap) - assign(*ap++, !COPYV); - for (ap = environ; *ap;) - export(lookup(*ap++)); + prs("+"); + for (i = 0; wp[i]; i++) { + if (i) + prs(" "); + prs(wp[i]); } - closeall(); - areanum = 1; + prs("\n"); +} - shell = lookup("SHELL"); - if (shell->value == null) - setval(shell, (char *)DEFAULT_SHELL); - export(shell); +static void closef(int i) +{ + if (i > 2) + close(i); +} - homedir = lookup("HOME"); - if (homedir->value == null) - setval(homedir, "/"); - export(homedir); +static void closeall(void) +{ + int u; - setval(lookup("$"), putn(getpid())); + for (u = NUFILE; u < NOFILE;) + close(u++); +} - path = lookup("PATH"); - if (path->value == null) { - if (geteuid() == 0) - setval(path, "/sbin:/bin:/usr/sbin:/usr/bin"); - else - setval(path, "/bin:/usr/bin"); - } - export(path); - ifs = lookup("IFS"); - if (ifs->value == null) - setval(ifs, " \t\n"); +/* fail but return to process next command */ +static void fail(void) ATTRIBUTE_NORETURN; +static void fail(void) +{ + longjmp(failpt, 1); + /* NOTREACHED */ +} -#ifdef MSHDEBUG - mshdbg_var = lookup("MSHDEBUG"); - if (mshdbg_var->value == null) - setval(mshdbg_var, "0"); -#endif +/* abort shell (or fail in subshell) */ +static void leave(void) ATTRIBUTE_NORETURN; +static void leave(void) +{ + DBGPRINTF(("LEAVE: leave called!\n")); - prompt = lookup("PS1"); -#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT - if (prompt->value == null) -#endif - setval(prompt, DEFAULT_USER_PROMPT); - if (geteuid() == 0) { - setval(prompt, DEFAULT_ROOT_PROMPT); - prompt->status &= ~EXPORT; + if (execflg) + fail(); + scraphere(); + freehere(1); + runtrap(0); + _exit(exstat); + /* NOTREACHED */ +} + +static void warn(const char *s) +{ + if (*s) { + prs(s); + exstat = -1; } - cprompt = lookup("PS2"); -#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT - if (cprompt->value == null) -#endif - setval(cprompt, "> "); + prs("\n"); + if (FLAG['e']) + leave(); +} - iof = filechar; - cflag = 0; - name = *argv++; - if (--argc >= 1) { - if (argv[0][0] == '-' && argv[0][1] != '\0') { - for (s = argv[0] + 1; *s; s++) - switch (*s) { - case 'c': - prompt->status &= ~EXPORT; - cprompt->status &= ~EXPORT; - setval(prompt, ""); - setval(cprompt, ""); - cflag = 1; - if (--argc > 0) - PUSHIO(aword, *++argv, iof = nlchar); - break; +static void err(const char *s) +{ + warn(s); + if (FLAG['n']) + return; + if (!interactive) + leave(); + if (e.errpt) + longjmp(e.errpt, 1); + closeall(); + e.iop = e.iobase = iostack; +} - case 'q': - qflag = SIG_DFL; - break; - case 's': - /* standard input */ - break; +/* -------- area.c -------- */ - case 't': - prompt->status &= ~EXPORT; - setval(prompt, ""); - iof = linechar; - break; +/* + * All memory between (char *)areabot and (char *)(areatop+1) is + * exclusively administered by the area management routines. + * It is assumed that sbrk() and brk() manipulate the high end. + */ - case 'i': - interactive++; - default: - if (*s >= 'a' && *s <= 'z') - flag[(int) *s]++; - } - } else { - argv--; - argc++; - } +#define sbrk(X) ({ \ + void * __q = (void *)-1; \ + if (brkaddr + (int)(X) < brktop) { \ + __q = brkaddr; \ + brkaddr += (int)(X); \ + } \ + __q; \ +}) - if (iof == filechar && --argc > 0) { - setval(prompt, ""); - setval(cprompt, ""); - prompt->status &= ~EXPORT; - cprompt->status &= ~EXPORT; +static void initarea(void) +{ + brkaddr = xmalloc(AREASIZE); + brktop = brkaddr + AREASIZE; -/* Shell is non-interactive, activate printf-based debug */ -#ifdef MSHDEBUG - mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0'); - if (mshdbg < 0) - mshdbg = 0; -#endif - DBGPRINTF(("MSH_MAIN: calling newfile()\n")); + while ((long) sbrk(0) & ALIGN) + sbrk(1); + areabot = (struct region *) sbrk(REGSIZE); - if (newfile(name = *++argv)) - exit(1); /* Exit on error */ + areabot->next = areabot; + areabot->area = BUSY; + areatop = areabot; + areanxt = areabot; +} + +static char *getcell(unsigned nbytes) +{ + int nregio; + struct region *p, *q; + int i; + + if (nbytes == 0) { + puts("getcell(0)"); + abort(); + } + /* silly and defeats the algorithm */ + /* + * round upwards and add administration area + */ + nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; + p = areanxt; + for (;;) { + if (p->area > areanum) { + /* + * merge free cells + */ + while ((q = p->next)->area > areanum && q != areanxt) + p->next = q->next; + /* + * exit loop if cell big enough + */ + if (q >= p + nregio) + goto found; + } + p = p->next; + if (p == areanxt) + break; + } + i = nregio >= GROWBY ? nregio : GROWBY; + p = (struct region *) sbrk(i * REGSIZE); + if (p == (struct region *) -1) + return NULL; + p--; + if (p != areatop) { + puts("not contig"); + abort(); /* allocated areas are contiguous */ + } + q = p + i; + p->next = q; + p->area = FREE; + q->next = areabot; + q->area = BUSY; + areatop = q; + found: + /* + * we found a FREE area big enough, pointed to by 'p', and up to 'q' + */ + areanxt = p + nregio; + if (areanxt < q) { + /* + * split into requested area and rest + */ + if (areanxt + 1 > q) { + puts("OOM"); + abort(); /* insufficient space left for admin */ } + areanxt->next = q; + areanxt->area = FREE; + p->next = areanxt; } + p->area = areanum; + return (char *) (p + 1); +} - setdash(); +static void freecell(char *cp) +{ + struct region *p; - /* This won't be true if PUSHIO has been called, say from newfile() above */ - if (e.iop < iostack) { - PUSHIO(afile, 0, iof); - if (isatty(0) && isatty(1) && !cflag) { - interactive++; -#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET -#ifdef MSHDEBUG - 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); -#endif - printf("Enter 'help' for a list of built-in commands.\n\n"); -#endif + p = (struct region *) cp; + if (p != NULL) { + p--; + if (p < areanxt) + areanxt = p; + p->area = FREE; + } +} +#define DELETE(obj) freecell((char *)obj) + +static void freearea(int a) +{ + struct region *p, *top; + + top = areatop; + for (p = areabot; p != top; p = p->next) + if (p->area >= a) + p->area = FREE; +} + +static void setarea(char *cp, int a) +{ + struct region *p; + + p = (struct region *) cp; + if (p != NULL) + (p - 1)->area = a; +} + +static int getarea(char *cp) +{ + return ((struct region *) cp - 1)->area; +} + +static void garbage(void) +{ + struct region *p, *q, *top; + + top = areatop; + for (p = areabot; p != top; p = p->next) { + if (p->area > areanum) { + while ((q = p->next)->area > areanum) + p->next = q->next; + areanxt = p; } } +#ifdef SHRINKBY + if (areatop >= q + SHRINKBY && q->area > areanum) { + brk((char *) (q + 1)); + q->next = areabot; + q->area = BUSY; + areatop = q; + } +#endif +} - signal(SIGQUIT, qflag); - if (name && name[0] == '-') { - interactive++; - if ((f = open(".profile", 0)) >= 0) - next(remap(f)); - if ((f = open("/etc/profile", 0)) >= 0) - next(remap(f)); +static char *space(int n) +{ + char *cp; + + cp = getcell(n); + if (cp == NULL) + err("out of string space"); + return cp; +} + +static char *strsave(const char *s, int a) +{ + char *cp; + + cp = space(strlen(s) + 1); + if (cp == NULL) { +// FIXME: I highly doubt this is good. + return (char*)""; } - if (interactive) - signal(SIGTERM, sig); + setarea(cp, a); + strcpy(cp, s); + return cp; +} - if (signal(SIGINT, SIG_IGN) != SIG_IGN) - signal(SIGINT, onintr); - dolv = argv; - dolc = argc; - dolv[0] = name; - if (dolc > 1) { - for (ap = ++argv; --argc > 0;) { - if (assign(*ap = *argv++, !COPYV)) { - dolc--; /* keyword */ - } else { - ap++; - } + +/* -------- var.c -------- */ + +static int eqname(const char *n1, const char *n2) +{ + for (; *n1 != '=' && *n1 != '\0'; n1++) + if (*n2++ != *n1) + return 0; + return *n2 == '\0' || *n2 == '='; +} + +static const char *findeq(const char *cp) +{ + while (*cp != '\0' && *cp != '=') + cp++; + return cp; +} + +/* + * Find the given name in the dictionary + * and return its value. If the name was + * not previously there, enter it now and + * return a null value. + */ +static struct var *lookup(const char *n) +{ +// FIXME: dirty hack + static struct var dummy; + + struct var *vp; + const char *cp; + char *xp; + int c; + + if (isdigit(*n)) { + dummy.name = (char*)n; + for (c = 0; isdigit(*n) && c < 1000; n++) + c = c * 10 + *n - '0'; + dummy.status = RONLY; + dummy.value = (c <= dolc ? dolv[c] : null); + return &dummy; + } + + for (vp = vlist; vp; vp = vp->next) + if (eqname(vp->name, n)) + return vp; + + cp = findeq(n); + vp = (struct var *) space(sizeof(*vp)); + if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { + dummy.name = dummy.value = (char*)""; + return &dummy; + } + + xp = vp->name; + while ((*xp = *n++) != '\0' && *xp != '=') + xp++; + *xp++ = '='; + *xp = '\0'; + setarea((char *) vp, 0); + setarea((char *) vp->name, 0); + vp->value = null; + vp->next = vlist; + vp->status = GETCELL; + vlist = vp; + return vp; +} + +/* + * if name is not NULL, it must be + * a prefix of the space `val', + * and end with `='. + * this is all so that exporting + * values is reasonably painless. + */ +static void nameval(struct var *vp, const char *val, const char *name) +{ + const char *cp; + char *xp; + int fl; + + if (vp->status & RONLY) { + xp = vp->name; + while (*xp && *xp != '=') + putc(*xp++, stderr); + err(" is read-only"); + return; + } + fl = 0; + if (name == NULL) { + xp = space(strlen(vp->name) + strlen(val) + 2); + if (xp == NULL) + return; + /* make string: name=value */ + setarea(xp, 0); + name = xp; + cp = vp->name; + while ((*xp = *cp++) != '\0' && *xp != '=') + xp++; + *xp++ = '='; + strcpy(xp, val); + val = xp; + fl = GETCELL; + } + if (vp->status & GETCELL) + freecell(vp->name); /* form new string `name=value' */ + vp->name = (char*)name; + vp->value = (char*)val; + vp->status |= fl; +} + +/* + * give variable at `vp' the value `val'. + */ +static void setval(struct var *vp, const char *val) +{ + nameval(vp, val, NULL); +} + +static void export(struct var *vp) +{ + vp->status |= EXPORT; +} + +static void ronly(struct var *vp) +{ + if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ + vp->status |= RONLY; +} + +static int isassign(const char *s) +{ + unsigned char c; + DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s)); + + c = *s; + /* no isalpha() - we shouldn't use locale */ + /* c | 0x20 - lowercase (Latin) letters */ + if (c != '_' && (unsigned)((c|0x20) - 'a') > 25) + /* not letter */ + return 0; + + while (1) { + c = *++s; + if (c == '=') + return 1; + if (c == '\0') + return 0; + if (c != '_' + && (unsigned)(c - '0') > 9 /* not number */ + && (unsigned)((c|0x20) - 'a') > 25 /* not letter */ + ) { + return 0; } } - 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)); +static int assign(const char *s, int cf) +{ + const char *cp; + struct var *vp; - for (;;) { - if (interactive && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING - current_prompt = prompt->value; -#else - prs(prompt->value); -#endif + DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf)); + + if (!isalpha(*s) && *s != '_') + return 0; + for (cp = s; *cp != '='; cp++) + if (*cp == '\0' || (!isalnum(*cp) && *cp != '_')) + return 0; + vp = lookup(s); + nameval(vp, ++cp, cf == COPYV ? NULL : s); + if (cf != COPYV) + vp->status &= ~GETCELL; + return 1; +} + +static int checkname(char *cp) +{ + DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp)); + + if (!isalpha(*cp++) && *(cp - 1) != '_') + return 0; + while (*cp) + if (!isalnum(*cp++) && *(cp - 1) != '_') + return 0; + return 1; +} + +static void putvlist(int f, int out) +{ + struct var *vp; + + for (vp = vlist; vp; vp = vp->next) { + if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { + if (vp->status & EXPORT) + write(out, "export ", 7); + if (vp->status & RONLY) + write(out, "readonly ", 9); + write(out, vp->name, (int) (findeq(vp->name) - vp->name)); + write(out, "\n", 1); } - onecommand(); - /* Ensure that getenv("PATH") stays current */ - setenv("PATH", path->value, 1); } +} - DBGPRINTF(("MSH_MAIN: returning.\n")); + +/* + * trap handling + */ +static void sig(int i) +{ + trapset = i; + signal(i, sig); } +static void runtrap(int i) +{ + char *trapstr; + + trapstr = trap[i]; + if (trapstr == NULL) + return; + + if (i == 0) + trap[i] = NULL; + + RUN(aword, trapstr, nlchar); +} + + static void setdash(void) { char *cp; @@ -989,9 +1291,9 @@ static void setdash(void) cp = m; for (c = 'a'; c <= 'z'; c++) - if (flag[(int) c]) + if (FLAG[c]) *cp++ = c; - *cp = 0; + *cp = '\0'; setval(lookup("-"), m); } @@ -1001,16 +1303,16 @@ static int newfile(char *s) DBGPRINTF7(("NEWFILE: opening %s\n", 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"); return 1; } - } else - f = 0; + } next(remap(f)); return 0; @@ -1041,7 +1343,7 @@ struct op *scantree(struct op *head) DBGPRINTF5(("SCANTREE: checking node %p\n", head)); - if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) { + if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) { DBGPRINTF5(("SCANTREE: dot found in node %p\n", head)); return head; } @@ -1074,9 +1376,10 @@ static void onecommand(void) intr = 0; execflg = 0; - setjmp(failpt = m1); /* Bruce Evans' fix */ - if (setjmp(failpt = m1) || yyparse() || intr) { - + failpt = m1; + setjmp(failpt); /* Bruce Evans' fix */ + failpt = m1; + if (setjmp(failpt) || yyparse() || intr) { DBGPRINTF(("ONECOMMAND: this is not good.\n")); while (e.oenv) @@ -1094,7 +1397,7 @@ 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); @@ -1105,55 +1408,13 @@ static void onecommand(void) leave(); } - if ((i = trapset) != 0) { + i = trapset; + if (i != 0) { trapset = 0; runtrap(i); } } -static void fail(void) -{ - longjmp(failpt, 1); - /* NOTREACHED */ -} - -static void leave(void) -{ - DBGPRINTF(("LEAVE: leave called!\n")); - - if (execflg) - fail(); - scraphere(); - freehere(1); - runtrap(0); - _exit(exstat); - /* NOTREACHED */ -} - -static void warn(char *s) -{ - if (*s) { - prs(s); - exstat = -1; - } - prs("\n"); - if (flag['e']) - leave(); -} - -static void err(char *s) -{ - warn(s); - if (flag['n']) - return; - if (!interactive) - leave(); - if (e.errpt) - longjmp(e.errpt, 1); - closeall(); - e.iop = e.iobase = iostack; -} - static int newenv(int f) { struct env *ep; @@ -1185,7 +1446,8 @@ static void quitenv(void) DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv)); - if ((ep = e.oenv) != NULL) { + ep = e.oenv; + if (ep != NULL) { fd = e.iofd; e = *ep; /* should close `'d files */ @@ -1196,23 +1458,23 @@ static void quitenv(void) } /* - * Is any character from s1 in s2? + * Is character c in s? */ -static int anys(char *s1, char *s2) +static int any(int c, const char *s) { - while (*s1) - if (any(*s1++, s2)) + while (*s) + if (*s++ == c) return 1; return 0; } /* - * Is character c in s? + * Is any character from s1 in s2? */ -static int any(int c, char *s) +static int anys(const char *s1, const char *s2) { - while (*s) - if (*s++ == c) + while (*s1) + if (any(*s1++, s2)) return 1; return 0; } @@ -1239,231 +1501,9 @@ static void onintr(int s) /* ANSI C requires a parameter */ } else if (heedint) { execflg = 0; leave(); - } -} - -static char *space(int n) -{ - char *cp; - - if ((cp = getcell(n)) == 0) - err("out of string space"); - return cp; -} - -static char *strsave(char *s, int a) -{ - char *cp, *xp; - - if ((cp = space(strlen(s) + 1)) != NULL) { - setarea((char *) cp, a); - for (xp = cp; (*xp++ = *s++) != '\0';); - return cp; - } - return ""; -} - -/* - * trap handling - */ -static void sig(int i) -{ - trapset = i; - signal(i, sig); -} - -static void runtrap(int i) -{ - char *trapstr; - - if ((trapstr = trap[i]) == NULL) - return; - - if (i == 0) - trap[i] = 0; - - RUN(aword, trapstr, nlchar); -} - -/* -------- var.c -------- */ - -/* - * Find the given name in the dictionary - * and return its value. If the name was - * not previously there, enter it now and - * return a null value. - */ -static struct var *lookup(char *n) -{ - struct var *vp; - char *cp; - int c; - static struct var dummy; - - if (isdigit(*n)) { - dummy.name = n; - for (c = 0; isdigit(*n) && c < 1000; n++) - c = c * 10 + *n - '0'; - dummy.status = RONLY; - dummy.value = c <= dolc ? dolv[c] : null; - return &dummy; - } - for (vp = vlist; vp; vp = vp->next) - if (eqname(vp->name, n)) - return vp; - cp = findeq(n); - vp = (struct var *) space(sizeof(*vp)); - if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { - dummy.name = dummy.value = ""; - return &dummy; - } - for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++); - if (*cp == 0) - *cp = '='; - *++cp = 0; - setarea((char *) vp, 0); - setarea((char *) vp->name, 0); - vp->value = null; - vp->next = vlist; - vp->status = GETCELL; - vlist = vp; - return vp; -} - -/* - * give variable at `vp' the value `val'. - */ -static void setval(struct var *vp, char *val) -{ - nameval(vp, val, (char *) NULL); -} - -/* - * if name is not NULL, it must be - * a prefix of the space `val', - * and end with `='. - * this is all so that exporting - * values is reasonably painless. - */ -static void nameval(struct var *vp, char *val, char *name) -{ - char *cp, *xp; - char *nv; - int fl; - - if (vp->status & RONLY) { - for (xp = vp->name; *xp && *xp != '=';) - putc(*xp++, stderr); - err(" is read-only"); - return; - } - fl = 0; - if (name == NULL) { - xp = space(strlen(vp->name) + strlen(val) + 2); - if (xp == 0) - return; - /* make string: name=value */ - setarea((char *) xp, 0); - name = xp; - for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++); - if (*xp++ == 0) - xp[-1] = '='; - nv = xp; - for (cp = val; (*xp++ = *cp++) != '\0';); - val = nv; - fl = GETCELL; - } - if (vp->status & GETCELL) - freecell(vp->name); /* form new string `name=value' */ - vp->name = name; - vp->value = val; - vp->status |= fl; -} - -static void export(struct var *vp) -{ - vp->status |= EXPORT; -} - -static void ronly(struct var *vp) -{ - if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ - vp->status |= RONLY; -} - -static int isassign(char *s) -{ - DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s)); - - if (!isalpha((int) *s) && *s != '_') - return 0; - for (; *s != '='; s++) - if (*s == 0 || (!isalnum(*s) && *s != '_')) - return 0; - - return 1; -} - -static int assign(char *s, int cf) -{ - char *cp; - struct var *vp; - - DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf)); - - if (!isalpha(*s) && *s != '_') - return 0; - for (cp = s; *cp != '='; cp++) - if (*cp == 0 || (!isalnum(*cp) && *cp != '_')) - return 0; - vp = lookup(s); - nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s); - if (cf != COPYV) - vp->status &= ~GETCELL; - return 1; -} - -static int checkname(char *cp) -{ - DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp)); - - if (!isalpha(*cp++) && *(cp - 1) != '_') - return 0; - while (*cp) - if (!isalnum(*cp++) && *(cp - 1) != '_') - return 0; - return 1; -} - -static void putvlist(int f, int out) -{ - struct var *vp; - - for (vp = vlist; vp; vp = vp->next) - if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { - if (vp->status & EXPORT) - write(out, "export ", 7); - if (vp->status & RONLY) - write(out, "readonly ", 9); - write(out, vp->name, (int) (findeq(vp->name) - vp->name)); - write(out, "\n", 1); - } -} - -static int eqname(char *n1, char *n2) -{ - for (; *n1 != '=' && *n1 != 0; n1++) - if (*n2++ != *n1) - return 0; - return *n2 == 0 || *n2 == '='; + } } -static char *findeq(char *cp) -{ - while (*cp != '\0' && *cp != '=') - cp++; - return cp; -} /* -------- gmatch.c -------- */ /* @@ -1475,20 +1515,45 @@ static char *findeq(char *cp) #define CMASK 0377 #define QUOTE 0200 -#define QMASK (CMASK&~QUOTE) +#define QMASK (CMASK & ~QUOTE) #define NOT '!' /* might use ^ */ -static int gmatch(char *s, char *p) +static const char *cclass(const char *p, int sub) +{ + int c, d, not, found; + + not = (*p == NOT); + if (not != 0) + p++; + found = not; + do { + if (*p == '\0') + return NULL; + c = *p & CMASK; + if (p[1] == '-' && p[2] != ']') { + d = p[2] & CMASK; + p++; + } else + d = c; + if (c == sub || (c <= sub && sub <= d)) + found = !not; + } while (*++p != ']'); + return found ? p + 1 : NULL; +} + +static int gmatch(const char *s, const char *p) { int sc, pc; if (s == NULL || p == NULL) return 0; + while ((pc = *p++ & CMASK) != '\0') { sc = *s++ & QMASK; switch (pc) { case '[': - if ((p = cclass(p, sc)) == NULL) + p = cclass(p, sc); + if (p == NULL) return 0; break; @@ -1510,187 +1575,33 @@ static int gmatch(char *s, char *p) return 0; } } - return *s == 0; -} - -static char *cclass(char *p, int sub) -{ - int c, d, not, found; - - if ((not = *p == NOT) != 0) - p++; - found = not; - do { - if (*p == '\0') - return NULL; - c = *p & CMASK; - if (p[1] == '-' && p[2] != ']') { - d = p[2] & CMASK; - p++; - } else - d = c; - if (c == sub || (c <= sub && sub <= d)) - found = !not; - } while (*++p != ']'); - return found ? p + 1 : NULL; + return *s == '\0'; } -/* -------- area.c -------- */ - +/* -------- csyn.c -------- */ /* - * All memory between (char *)areabot and (char *)(areatop+1) is - * exclusively administered by the area management routines. - * It is assumed that sbrk() and brk() manipulate the high end. + * shell: syntax (C version) */ -#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;}) - -static void initarea(void) -{ - brkaddr = xmalloc(AREASIZE); - brktop = brkaddr + AREASIZE; - - while ((long) sbrk(0) & ALIGN) - sbrk(1); - areabot = (struct region *) sbrk(REGSIZE); - - areabot->next = areabot; - areabot->area = BUSY; - areatop = areabot; - areanxt = areabot; -} - -char *getcell(unsigned nbytes) -{ - int nregio; - struct region *p, *q; - int i; - - if (nbytes == 0) { - puts("getcell(0)"); - abort(); - } - /* silly and defeats the algorithm */ - /* - * round upwards and add administration area - */ - nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; - for (p = areanxt;;) { - if (p->area > areanum) { - /* - * merge free cells - */ - while ((q = p->next)->area > areanum && q != areanxt) - p->next = q->next; - /* - * exit loop if cell big enough - */ - if (q >= p + nregio) - goto found; - } - p = p->next; - if (p == areanxt) - break; - } - i = nregio >= GROWBY ? nregio : GROWBY; - p = (struct region *) sbrk(i * REGSIZE); - if (p == (struct region *) -1) - return NULL; - p--; - if (p != areatop) { - puts("not contig"); - abort(); /* allocated areas are contiguous */ - } - q = p + i; - p->next = q; - p->area = FREE; - q->next = areabot; - q->area = BUSY; - areatop = q; - found: - /* - * we found a FREE area big enough, pointed to by 'p', and up to 'q' - */ - areanxt = p + nregio; - if (areanxt < q) { - /* - * split into requested area and rest - */ - if (areanxt + 1 > q) { - puts("OOM"); - abort(); /* insufficient space left for admin */ - } - areanxt->next = q; - areanxt->area = FREE; - p->next = areanxt; - } - p->area = areanum; - return (char *) (p + 1); -} - -static void freecell(char *cp) +static void yyerror(const char *s) ATTRIBUTE_NORETURN; +static void yyerror(const char *s) { - struct region *p; - - if ((p = (struct region *) cp) != NULL) { - p--; - if (p < areanxt) - areanxt = p; - p->area = FREE; + yynerrs++; + if (interactive && e.iop <= iostack) { + multiline = 0; + while (eofc() == 0 && yylex(0) != '\n'); } + err(s); + fail(); } -static void freearea(int a) -{ - struct region *p, *top; - - top = areatop; - for (p = areabot; p != top; p = p->next) - if (p->area >= a) - p->area = FREE; -} - -static void setarea(char *cp, int a) -{ - struct region *p; - - if ((p = (struct region *) cp) != NULL) - (p - 1)->area = a; -} - -int getarea(char *cp) -{ - return ((struct region *) cp - 1)->area; -} - -static void garbage(void) +static void zzerr(void) ATTRIBUTE_NORETURN; +static void zzerr(void) { - struct region *p, *q, *top; - - top = areatop; - for (p = areabot; p != top; p = p->next) { - if (p->area > areanum) { - while ((q = p->next)->area > areanum) - p->next = q->next; - areanxt = p; - } - } -#ifdef SHRINKBY - if (areatop >= q + SHRINKBY && q->area > areanum) { - brk((char *) (q + 1)); - q->next = areabot; - q->area = BUSY; - areatop = q; - } -#endif + yyerror("syntax error"); } -/* -------- csyn.c -------- */ -/* - * shell: syntax (C version) - */ - int yyparse(void) { DBGPRINTF7(("YYPARSE: enter...\n")); @@ -1716,9 +1627,10 @@ static struct op *pipeline(int cf) if (t != NULL) { while ((c = yylex(0)) == '|') { - if ((p = command(CONTIN)) == NULL) { + p = command(CONTIN); + if (p == NULL) { DBGPRINTF8(("PIPELINE: error!\n")); - SYNTAXERR; + zzerr(); } if (t->type != TPAREN && t->type != TCOM) { @@ -1748,9 +1660,10 @@ static struct op *andor(void) if (t != NULL) { while ((c = yylex(0)) == LOGAND || c == LOGOR) { - if ((p = pipeline(CONTIN)) == NULL) { + p = pipeline(CONTIN); + if (p == NULL) { DBGPRINTF8(("ANDOR: error!\n")); - SYNTAXERR; + zzerr(); } t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS); @@ -1773,16 +1686,19 @@ static struct op *c_list(void) t = andor(); if (t != NULL) { - if ((peeksym = yylex(0)) == '&') + peeksym = yylex(0); + if (peeksym == '&') t = block(TASYNC, t, NOBLOCK, NOWORDS); while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) { - if ((p = andor()) == NULL) + p = andor(); + if (p== NULL) return t; - if ((peeksym = yylex(0)) == '&') + peeksym = yylex(0); + if (peeksym == '&') p = block(TASYNC, p, NOBLOCK, NOWORDS); t = list(t, p); @@ -1803,7 +1719,8 @@ static int synio(int cf) DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf)); - if ((c = yylex(cf)) != '<' && c != '>') { + c = yylex(cf); + if (c != '<' && c != '>') { peeksym = c; return 0; } @@ -1822,9 +1739,10 @@ static int synio(int cf) static void musthave(int c, int cf) { - if ((peeksym = yylex(cf)) != c) { + peeksym = yylex(cf); + if (peeksym != c) { DBGPRINTF7(("MUSTHAVE: error!\n")); - SYNTAXERR; + zzerr(); } peeksym = 0; @@ -1892,7 +1810,8 @@ static struct op *command(int cf) switch (c) { default: peeksym = c; - if ((t = simple()) == NULL) { + t = simple(); + if (t == NULL) { if (iolist == NULL) return NULL; t = newtp(); @@ -1916,7 +1835,8 @@ static struct op *command(int cf) t->str = yylval.cp; multiline++; t->words = wordlist(); - if ((c = yylex(0)) != '\n' && c != ';') + c = yylex(0); + if (c != '\n' && c != ';') peeksym = c; t->left = dogroup(0); multiline--; @@ -2006,7 +1926,7 @@ static struct op *dogroup(int onlydone) if (c == DONE && onlydone) return NULL; if (c != DO) - SYNTAXERR; + zzerr(); mylist = c_list(); musthave(DONE, 0); return mylist; @@ -2017,7 +1937,8 @@ static struct op *thenpart(void) int c; struct op *t; - if ((c = yylex(0)) != THEN) { + c = yylex(0); + if (c != THEN) { peeksym = c; return NULL; } @@ -2025,7 +1946,7 @@ static struct op *thenpart(void) t->type = 0; t->left = c_list(); if (t->left == NULL) - SYNTAXERR; + zzerr(); t->right = elsepart(); return t; } @@ -2037,8 +1958,9 @@ static struct op *elsepart(void) switch (c = yylex(0)) { case ELSE: - if ((t = c_list()) == NULL) - SYNTAXERR; + t = c_list(); + if (t == NULL) + zzerr(); return t; case ELIF: @@ -2079,7 +2001,8 @@ static struct op *casepart(void) t->words = pattern(); musthave(')', 0); t->left = c_list(); - if ((peeksym = yylex(CONTIN)) != ESAC) + peeksym = yylex(CONTIN); + if (peeksym != ESAC) musthave(BREAK, CONTIN); DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t)); @@ -2096,7 +2019,8 @@ static char **pattern(void) musthave(WORD, cf); word(yylval.cp); cf = 0; - } while ((c = yylex(0)) == '|'); + c = yylex(0); + } while (c == '|'); peeksym = c; word(NOWORD); @@ -2107,7 +2031,8 @@ static char **wordlist(void) { int c; - if ((c = yylex(0)) != IN) { + c = yylex(0); + if (c != IN) { peeksym = c; return NULL; } @@ -2188,7 +2113,6 @@ 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)); @@ -2210,7 +2134,6 @@ static struct op *namelist(struct op *t) word(NOWORD); t->words = copyw(); - return t; } @@ -2249,35 +2172,19 @@ static struct ioword *io(int u, int f, char *cp) return iop; } -static void zzerr(void) -{ - yyerror("syntax error"); -} - -static void yyerror(char *s) -{ - yynerrs++; - if (interactive && e.iop <= iostack) { - multiline = 0; - while (eofc() == 0 && yylex(0) != '\n'); - } - err(s); - fail(); -} - static int yylex(int cf) { int c, c1; int atstart; - if ((c = peeksym) > 0) { + c = peeksym; + if (c > 0) { peeksym = 0; if (c == '\n') startl = 1; return c; } - nlseen = 0; atstart = startl; startl = 0; @@ -2287,14 +2194,15 @@ static int yylex(int cf) /* MALAMO */ line[LINELIM - 1] = '\0'; - loop: + loop: while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */ ; switch (c) { default: if (any(c, "0123456789")) { - unget(c1 = my_getc(0)); + c1 = my_getc(0); + unget(c1); if (c1 == '<' || c1 == '>') { iounit = c - '0'; goto loop; @@ -2305,7 +2213,7 @@ static int yylex(int cf) break; case '#': /* Comment, skip to next newline or End-of-string */ - while ((c = my_getc(0)) != 0 && c != '\n'); + while ((c = my_getc(0)) != '\0' && c != '\n'); unget(c); goto loop; @@ -2316,8 +2224,10 @@ static int yylex(int cf) case '$': DBGPRINTF9(("YYLEX: found $\n")); *e.linep++ = c; - if ((c = my_getc(0)) == '{') { - if ((c = collect(c, '}')) != '\0') + c = my_getc(0); + if (c == '{') { + c = collect(c, '}'); + if (c != '\0') return c; goto pack; } @@ -2326,7 +2236,8 @@ static int yylex(int cf) case '`': case '\'': case '"': - if ((c = collect(c, c)) != '\0') + c = collect(c, c); + if (c != '\0') return c; goto pack; @@ -2335,10 +2246,10 @@ static int yylex(int cf) case ';': startl = 1; /* If more chars process them, else return NULL char */ - if ((c1 = dual(c)) != '\0') + c1 = dual(c); + if (c1 != '\0') return c1; - else - return c; + return c; case '^': startl = 1; @@ -2354,7 +2265,7 @@ static int yylex(int cf) startl = 1; if (multiline || cf & CONTIN) { if (interactive && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); @@ -2373,8 +2284,8 @@ static int yylex(int cf) unget(c); - pack: - while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) { + pack: + while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) { if (e.linep >= elinep) err("word too long"); else @@ -2388,9 +2299,12 @@ static int yylex(int cf) *e.linep++ = '\0'; - if (atstart && (c = rlookup(line)) != 0) { - startl = 1; - return c; + if (atstart) { + c = rlookup(line); + if (c != 0) { + startl = 1; + return c; + } } yylval.cp = strsave(line, areanum); @@ -2415,7 +2329,7 @@ static int collect(int c, int c1) return YYERRCODE; } if (interactive && c == '\n' && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); @@ -2440,15 +2354,15 @@ static int dual(int c) DBGPRINTF8(("DUAL: enter, c=%d\n", c)); - *cp++ = c; /* c is the given "peek" char */ - *cp++ = my_getc(0); /* get next char of input */ - *cp = 0; /* add EOS marker */ + *cp++ = c; /* c is the given "peek" char */ + *cp++ = my_getc(0); /* get next char of input */ + *cp = '\0'; /* add EOS marker */ - c = rlookup(s); /* see if 2 chars form a shell multiline */ + c = rlookup(s); /* see if 2 chars form a shell multiline */ if (c == 0) - unget(*--cp); /* String is not a shell multiline, put peek char back */ + unget(*--cp); /* String is not a shell multiline, put peek char back */ - return c; /* String is multiline, return numeric multiline (restab) code */ + return c; /* String is multiline, return numeric multiline (restab) code */ } static void diag(int ec) @@ -2461,10 +2375,10 @@ static void diag(int ec) if (c == '>' || c == '<') { if (c != ec) zzerr(); - yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE; + yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE); c = my_getc(0); } else - yylval.i = ec == '>' ? IOWRITE : IOREAD; + yylval.i = (ec == '>' ? IOWRITE : IOREAD); if (c != '&' || yylval.i == IOHERE) unget(c); else @@ -2475,30 +2389,78 @@ static char *tree(unsigned size) { char *t; - if ((t = getcell(size)) == NULL) { - DBGPRINTF2(("TREE: getcell(%d) failed!\n", size)); - prs("command line too complicated\n"); - fail(); - /* NOTREACHED */ + t = getcell(size); + if (t == NULL) { + DBGPRINTF2(("TREE: getcell(%d) failed!\n", size)); + prs("command line too complicated\n"); + fail(); + /* NOTREACHED */ + } + return t; +} + + +/* VARARGS1 */ +/* ARGSUSED */ + +/* -------- exec.c -------- */ + +static struct op **find1case(struct op *t, const char *w) +{ + struct op *t1; + struct op **tp; + char **wp; + char *cp; + + if (t == NULL) { + DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n")); + return NULL; + } + + DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type, + T_CMD_NAMES[t->type])); + + if (t->type == TLIST) { + tp = find1case(t->left, w); + if (tp != NULL) { + DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp)); + return tp; + } + t1 = t->right; /* TPAT */ + } else + t1 = t; + + for (wp = t1->words; *wp;) { + cp = evalstr(*wp++, DOSUB); + if (cp && gmatch(w, cp)) { + DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n", + &t1->left)); + return &t1->left; + } } - return t; + + DBGPRINTF(("FIND1CASE: returning NULL\n")); + return NULL; } -/* VARARGS1 */ -/* ARGSUSED */ +static struct op *findcase(struct op *t, const char *w) +{ + struct op **tp; -/* -------- exec.c -------- */ + tp = find1case(t, w); + return tp != NULL ? *tp : NULL; +} /* * execute tree */ - static int execute(struct op *t, int *pin, int *pout, int act) { struct op *t1; volatile int i, rv, a; - char *cp, **wp, **wp2; + const char *cp; + char **wp, **wp2; struct var *vp; struct op *outtree_save; struct brkcon bc; @@ -2547,16 +2509,15 @@ static int execute(struct op *t, int *pin, int *pout, int act) break; case TCOM: - { - rv = forkexec(t, pin, pout, act, wp); - } + rv = forkexec(t, pin, pout, act, wp); break; case TPIPE: { int pv[2]; - if ((rv = openpipe(pv)) < 0) + rv = openpipe(pv); + if (rv < 0) break; pv[0] = remap(pv[0]); pv[1] = remap(pv[1]); @@ -2577,20 +2538,7 @@ static int execute(struct op *t, int *pin, int *pout, int act) DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n")); i = vfork(); - if (i != 0) { - interactive = hinteractive; - if (i != -1) { - setval(lookup("!"), putn(i)); - if (pin != NULL) - closepipe(pin); - if (interactive) { - prs(putn(i)); - prs("\n"); - } - } else - rv = -1; - setstatus(rv); - } else { + if (i == 0) { /* child */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); if (interactive) @@ -2598,24 +2546,38 @@ 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)); } + interactive = hinteractive; + if (i != -1) { + setval(lookup("!"), putn(i)); + if (pin != NULL) + closepipe(pin); + if (interactive) { + prs(putn(i)); + prs("\n"); + } + } else + rv = -1; + setstatus(rv); } break; case TOR: case TAND: rv = execute(t->left, pin, pout, 0); - if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND)) + t1 = t->right; + if (t1 != NULL && (rv == 0) == (t->type == TAND)) rv = execute(t1, pin, pout, 0); break; case TFOR: if (wp == NULL) { wp = dolv + 1; - if ((i = dolc) < 0) + i = dolc; + if (i < 0) i = 0; } else { i = -1; @@ -2655,14 +2617,16 @@ static int execute(struct op *t, int *pin, int *pout, int act) break; case TCASE: - if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0) + cp = evalstr(t->str, DOSUB | DOTRIM); + if (cp == NULL) cp = ""; DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n", ((t->str == NULL) ? "NULL" : t->str), ((cp == NULL) ? "NULL" : cp))); - if ((t1 = findcase(t->left, cp)) != NULL) { + 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); DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1)); @@ -2671,20 +2635,25 @@ static int execute(struct op *t, int *pin, int *pout, int act) case TBRACE: /* - if (iopp = t->ioact) + iopp = t->ioact; + if (i) while (*iopp) if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { rv = -1; break; } */ - if (rv >= 0 && (t1 = t->left)) - rv = execute(t1, pin, pout, 0); + if (rv >= 0) { + t1 = t->left; + if (t1) { + rv = execute(t1, pin, pout, 0); + } + } break; }; - broken: + broken: t->words = wp2; isbreak = 0; freehere(areanum); @@ -2695,7 +2664,8 @@ static int execute(struct op *t, int *pin, int *pout, int act) fail(); } - if ((i = trapset) != 0) { + i = trapset; + if (i != 0) { trapset = 0; runtrap(i); } @@ -2704,14 +2674,25 @@ static int execute(struct op *t, int *pin, int *pout, int act) return rv; } -static int -forkexec(struct op *t, int *pin, int *pout, int act, char **wp) +typedef int (*builtin_func_ptr)(struct op *); + +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) { pid_t newpid; int i, rv; - int (*shcom) (struct op *) = NULL; + builtin_func_ptr shcom = NULL; int f; - char *cp = NULL; + const char *cp = NULL; struct ioword **iopp; int resetsig; char **owp; @@ -2745,22 +2726,25 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) resetsig = 0; rv = -1; /* system-detected error */ if (t->type == TCOM) { - while ((cp = *wp++) != NULL); + while (*wp++ != NULL) + continue; cp = *wp; /* strip all initial assignments */ /* not correct wrt PATH=yyy command etc */ - if (flag['x']) { + 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)); + while ((cp = *owp++) != NULL && assign(cp, COPYV)) + continue; DBGPRINTF(("FORKEXEC: returning setstatus()\n")); return setstatus(0); - } else if (cp != NULL) { + } + if (cp != NULL) { shcom = inbuilt(cp); } } @@ -2790,9 +2774,7 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) return -1; } - - if (newpid > 0) { /* Parent */ - + if (newpid > 0) { /* Parent */ /* Restore values */ pin = hpin; pout = hpout; @@ -2801,12 +2783,10 @@ 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); @@ -2828,7 +2808,6 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) execflg = 0; } - if (owp != NULL) while ((cp = *owp++) != NULL && assign(cp, COPYV)) if (shcom == NULL) @@ -2844,15 +2823,16 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) #endif if (pin != NULL) { - dup2(pin[0], 0); - closepipe(pin); + xmove_fd(pin[0], 0); + if (pin[1] != 0) close(pin[1]); } if (pout != NULL) { - dup2(pout[1], 1); - closepipe(pout); + xmove_fd(pout[1], 1); + if (pout[1] != 1) close(pout[0]); } - if ((iopp = t->ioact) != NULL) { + iopp = t->ioact; + if (iopp != NULL) { if (shcom != NULL && shcom != doexec) { prs(cp); err(": cannot redirect shell command"); @@ -2910,7 +2890,8 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) static int iosetup(struct ioword *iop, int pipein, int pipeout) { int u = -1; - char *cp = NULL, *msg; + char *cp = NULL; + const char *msg; DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop, pipein, pipeout)); @@ -2926,8 +2907,9 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout) msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create"; if ((iop->io_flag & IOHERE) == 0) { - cp = iop->io_name; - if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL) + cp = iop->io_name; /* huh?? */ + cp = evalstr(cp, DOSUB | DOTRIM); + if (cp == NULL) return 1; } @@ -2943,17 +2925,18 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout) } switch (iop->io_flag) { case IOREAD: - u = open(cp, 0); + u = open(cp, O_RDONLY); break; case IOHERE: case IOHERE | IOXHERE: u = herein(iop->io_name, iop->io_flag & IOXHERE); - cp = "here file"; + cp = (char*)"here file"; break; case IOWRITE | IOCAT: - if ((u = open(cp, 1)) >= 0) { + u = open(cp, O_WRONLY); + if (u >= 0) { lseek(u, (long) 0, SEEK_END); break; } @@ -2974,69 +2957,12 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout) prs(": cannot "); warn(msg); return 1; - } else { - if (u != iop->io_unit) { - dup2(u, iop->io_unit); - close(u); - } } - return 0; -} - -static void echo(char **wp) -{ - int i; - - prs("+"); - for (i = 0; wp[i]; i++) { - if (i) - prs(" "); - prs(wp[i]); - } - prs("\n"); -} - -static struct op **find1case(struct op *t, char *w) -{ - struct op *t1; - struct op **tp; - char **wp, *cp; - - - if (t == NULL) { - DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n")); - return NULL; + if (u != iop->io_unit) { + dup2(u, iop->io_unit); + close(u); } - - DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type, - T_CMD_NAMES[t->type])); - - if (t->type == TLIST) { - if ((tp = find1case(t->left, w)) != NULL) { - DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp)); - return tp; - } - t1 = t->right; /* TPAT */ - } else - t1 = t; - - for (wp = t1->words; *wp;) - if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) { - DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n", - &t1->left)); - return &t1->left; - } - - DBGPRINTF(("FIND1CASE: returning NULL\n")); - return NULL; -} - -static struct op *findcase(struct op *t, char *w) -{ - struct op **tp; - - tp = find1case(t, w); - return tp != NULL ? *tp : NULL; + return 0; } /* @@ -3069,7 +2995,8 @@ static int waitfor(int lastpid, int canintr) if (errno != EINTR || canintr) break; } else { - if ((rv = WAITSIG(s)) != 0) { + rv = WAITSIG(s); + if (rv != 0) { if (rv < NSIGNAL) { if (signame[rv] != NULL) { if (pid != lastpid) { @@ -3122,18 +3049,18 @@ static int setstatus(int s) * If getenv("PATH") were kept up-to-date, * execvp might be used. */ -static char *rexecve(char *c, char **v, char **envp) +static const char *rexecve(char *c, char **v, char **envp) { int i; - char *sp, *tp; + const char *sp; + char *tp; int eacces = 0, asis = 0; char *name = c; - if (ENABLE_FEATURE_SH_STANDALONE_SHELL) { - optind = 1; + if (ENABLE_FEATURE_SH_STANDALONE) { if (find_applet_by_name(name)) { /* We have to exec here since we vforked. Running - * run_applet_by_name() won't work and bad things + * run_applet_and_exit() won't work and bad things * will happen. */ execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp); } @@ -3142,15 +3069,17 @@ static char *rexecve(char *c, char **v, char **envp) DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp)); sp = any('/', c) ? "" : path->value; - asis = *sp == '\0'; + asis = (*sp == '\0'); while (asis || *sp != '\0') { asis = 0; tp = e.linep; - for (; *sp != '\0'; tp++) - if ((*tp = *sp++) == ':') { - asis = *sp == '\0'; + for (; *sp != '\0'; tp++) { + *tp = *sp++; + if (*tp == ':') { + asis = (*sp == '\0'); break; } + } if (tp != e.linep) *tp++ = '/'; for (i = 0; (*tp++ = c[i++]) != '\0';); @@ -3210,13 +3139,15 @@ static int run(struct ioarg *argp, int (*f) (struct ioarg *)) ofail = failpt; rv = -1; - if (newenv(setjmp(errpt = ev)) == 0) { + errpt = ev; + if (newenv(setjmp(errpt)) == 0) { wdlist = 0; iolist = 0; pushio(argp, f); e.iobase = e.iop; yynerrs = 0; - if (setjmp(failpt = rt) == 0 && yyparse() == 0) + failpt = rt; + if (setjmp(failpt) == 0 && yyparse() == 0) rv = execute(outtree, NOPIPE, NOPIPE, 0); quitenv(); } else { @@ -3246,29 +3177,27 @@ static int dohelp(struct op *t) puts("\nBuilt-in commands:\n" "-------------------"); - for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) { - if (!x->name) - continue; - col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name); + col = 0; + x = builtincmds; + while (x->name) { + col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name); if (col > 60) { puts(""); col = 0; } + x++; } -#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL +#if ENABLE_FEATURE_SH_STANDALONE { - int i; - const struct BB_applet *applet; - - for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) { - if (!applet->name) - continue; + const struct bb_applet *applet = applets; - col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name); + while (applet->name) { + col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name); if (col > 60) { puts(""); col = 0; } + applet++; } } #endif @@ -3276,8 +3205,6 @@ static int dohelp(struct op *t) return EXIT_SUCCESS; } - - static int dolabel(struct op *t) { return 0; @@ -3285,14 +3212,20 @@ static int dolabel(struct op *t) static int dochdir(struct op *t) { - char *cp, *er; + const char *cp, *er; - if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) + cp = t->words[1]; + if (cp == NULL) { + cp = homedir->value; + if (cp != NULL) + goto do_cd; er = ": no home directory"; - else if (chdir(cp) < 0) + } else { + do_cd: + if (chdir(cp) >= 0) + return 0; er = ": bad directory"; - else - return 0; + } prs(cp != NULL ? cp : "cd"); err(er); return 1; @@ -3319,7 +3252,7 @@ static int doshift(struct op *t) */ static int dologin(struct op *t) { - char *cp; + const char *cp; if (interactive) { signal(SIGINT, SIG_DFL); @@ -3337,13 +3270,15 @@ static int doumask(struct op *t) int i, n; char *cp; - if ((cp = t->words[1]) == NULL) { + cp = t->words[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); } else { +/* huh??? '8','9' are not allowed! */ for (n = 0; *cp >= '0' && *cp <= '9'; cp++) n = n * 8 + (*cp - '0'); umask(n); @@ -3363,7 +3298,8 @@ static int doexec(struct op *t) return 1; execflg = 1; ofail = failpt; - if (setjmp(failpt = ex) == 0) + failpt = ex; + if (setjmp(failpt) == 0) execute(t, NOPIPE, NOPIPE, FEXEC); failpt = ofail; execflg = 0; @@ -3373,18 +3309,19 @@ static int doexec(struct op *t) static int dodot(struct op *t) { int i; - char *sp, *tp; + const char *sp; + char *tp; 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))); - if ((cp = t->words[1]) == NULL) { + cp = t->words[1]; + if (cp == NULL) { DBGPRINTF(("DODOT: bad args, ret 0\n")); return 0; - } else { - DBGPRINTF(("DODOT: cp is %s\n", cp)); } + DBGPRINTF(("DODOT: cp is %s\n", cp)); sp = any('/', cp) ? ":" : path->value; @@ -3402,7 +3339,8 @@ static int dodot(struct op *t) for (i = 0; (*tp++ = cp[i++]) != '\0';); /* Original code */ - if ((i = open(e.linep, 0)) >= 0) { + i = open(e.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)); @@ -3413,8 +3351,7 @@ static int dodot(struct op *t) return exstat; } - - } /* While */ + } /* while */ prs(cp); err(": not found"); @@ -3427,7 +3364,8 @@ static int dowait(struct op *t) int i; char *cp; - if ((cp = t->words[1]) != NULL) { + cp = t->words[1]; + if (cp != NULL) { i = getn(cp); if (i == 0) return 0; @@ -3448,11 +3386,15 @@ static int doread(struct op *t) return 1; } for (wp = t->words + 1; *wp; wp++) { - for (cp = e.linep; !nl && cp < elinep - 1; cp++) - if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) || - (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value))) + for (cp = e.linep; !nl && cp < elinep - 1; cp++) { + nb = read(0, cp, sizeof(*cp)); + if (nb != sizeof(*cp)) + break; + nl = (*cp == '\n'); + if (nl || (wp[1] && any(*cp, ifs->value))) break; - *cp = 0; + } + *cp = '\0'; if (nb <= 0) break; setval(lookup(*wp), e.linep); @@ -3492,12 +3434,12 @@ static int dotrap(struct op *t) } else setsig(n, SIG_IGN); } else { - if (interactive) + if (interactive) { if (n == SIGINT) setsig(n, onintr); else setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); - else + } else setsig(n, SIG_DFL); } } @@ -3508,7 +3450,8 @@ static int getsig(char *s) { int n; - if ((n = getn(s)) < 0 || n > _NSIG) { + n = getn(s); + if (n < 0 || n > _NSIG) { err("trap: bad signal number"); n = 0; } @@ -3564,7 +3507,8 @@ static int brkcontin(char *cp, int val) if (nl <= 0) nl = 999; do { - if ((bc = brklist) == NULL) + bc = brklist; + if (bc == NULL) break; brklist = bc->nextlev; } while (--nl); @@ -3582,7 +3526,8 @@ static int doexit(struct op *t) char *cp; execflg = 0; - if ((cp = t->words[1]) != NULL) + cp = t->words[1]; + if (cp != NULL) setstatus(getn(cp)); DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t)); @@ -3639,7 +3584,8 @@ static int doset(struct op *t) char *cp; int n; - if ((cp = t->words[1]) == NULL) { + cp = t->words[1]; + if (cp == NULL) { for (vp = vlist; vp; vp = vp->next) varput(vp->name, 1); return 0; @@ -3648,20 +3594,22 @@ static int doset(struct op *t) /* bad: t->words++; */ for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++); if (*++cp == 0) - flag['x'] = flag['v'] = 0; - else - for (; *cp; cp++) + 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]) { @@ -3692,7 +3640,7 @@ static void varput(char *s, int out) static int dotimes(struct op *t) { struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); + long clk_tck = sysconf(_SC_CLK_TCK); times(&buf); printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", @@ -3708,16 +3656,6 @@ static int dotimes(struct op *t) } -static int (*inbuilt(char *s)) (struct op *) { - const struct builtincmd *bp; - - for (bp = builtincmds; bp->name != NULL; bp++) - if (strcmp(bp->name, s) == 0) - return bp->builtinfunc; - - return NULL; -} - /* -------- eval.c -------- */ /* @@ -3746,17 +3684,18 @@ static char **eval(char **ap, int f) wp = NULL; wb = NULL; wf = NULL; - if (newenv(setjmp(errpt = ev)) == 0) { + errpt = ev; + 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)) + if (!FLAG['k'] || !isassign(*ap)) expand(*ap, &wb, f & ~DOKEY); } wb = addword((char *) 0, wb); @@ -3768,6 +3707,7 @@ static char **eval(char **ap, int f) return gflg ? (char **) NULL : wp; } + /* * Make the exported environment from the exported * names in the dictionary. Keyword assignments @@ -3786,26 +3726,10 @@ static char **makenv(int all, struct wdblock *wb) return getwords(wb); } -static char *evalstr(char *cp, int f) -{ - struct wdblock *wb; - - DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f)); - - wb = NULL; - if (expand(cp, &wb, f)) { - if (wb == NULL || wb->w_nword == 0 - || (cp = wb->w_words[0]) == NULL) - cp = ""; - DELETE(wb); - } else - cp = NULL; - return cp; -} - -static int expand(char *cp, struct wdblock **wbp, int f) +static int expand(const char *cp, struct wdblock **wbp, int f) { jmp_buf ev; + char *xp; #if __GNUC__ /* Avoid longjmp clobbering */ @@ -3819,26 +3743,28 @@ static int expand(char *cp, struct wdblock **wbp, int f) if (cp == NULL) return 0; - if (!anys("$`'\"", cp) && - !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) { - cp = strsave(cp, areanum); + if (!anys("$`'\"", cp) && !anys(ifs->value, cp) + && ((f & DOGLOB) == 0 || !anys("[*?", cp)) + ) { + xp = strsave(cp, areanum); if (f & DOTRIM) - unquote(cp); - *wbp = addword(cp, *wbp); + unquote(xp); + *wbp = addword(xp, *wbp); return 1; } - if (newenv(setjmp(errpt = ev)) == 0) { + errpt = ev; + if (newenv(setjmp(errpt)) == 0) { PUSHIO(aword, cp, strchar); e.iobase = e.iop; - while ((cp = blank(f)) && gflg == 0) { - e.linep = cp; - cp = strsave(cp, areanum); + while ((xp = blank(f)) && gflg == 0) { + e.linep = xp; + xp = strsave(xp, areanum); if ((f & DOGLOB) == 0) { if (f & DOTRIM) - unquote(cp); - *wbp = addword(cp, *wbp); + unquote(xp); + *wbp = addword(xp, *wbp); } else - *wbp = glob(cp, *wbp); + *wbp = glob(xp, *wbp); } quitenv(); } else @@ -3846,6 +3772,29 @@ static int expand(char *cp, struct wdblock **wbp, int f) return gflg == 0; } +static char *evalstr(char *cp, int f) +{ + struct wdblock *wb; + + DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f)); + + wb = NULL; + if (expand(cp, &wb, f)) { + if (wb == NULL || wb->w_nword == 0 + || (cp = wb->w_words[0]) == NULL + ) { +// TODO: I suspect that +// char *evalstr(char *cp, int f) is actually +// const char *evalstr(const char *cp, int f)! + cp = (char*)""; + } + DELETE(wb); + } else + cp = NULL; + return cp; +} + + /* * Blank interpretation and quoting */ @@ -3861,8 +3810,9 @@ static char *blank(int f) scanequals = f & DOKEY; foundequals = 0; - loop: - switch (c = subgetc('"', foundequals)) { + loop: + c = subgetc('"', foundequals); + switch (c) { case 0: if (sp == e.linep) return 0; @@ -3924,7 +3874,7 @@ static int subgetc(char ec, int quoted) DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted)); - again: + again: c = my_getc(ec); if (!INSUB() && ec != '\'') { if (c == '`') { @@ -3933,9 +3883,12 @@ static int subgetc(char ec, int quoted) e.iop->task = XGRAVE; goto again; } - if (c == '$' && (c = dollar(quoted)) == 0) { - e.iop->task = XDOLL; - goto again; + if (c == '$') { + c = dollar(quoted); + if (c == 0) { + e.iop->task = XDOLL; + goto again; + } } } return c; @@ -4003,11 +3956,12 @@ static int dollar(int quoted) return 0; } else { /* trap the nasty ${=} */ s[0] = '1'; - s[1] = 0; + s[1] = '\0'; } } vp = lookup(s); - if ((dolp = vp->value) == null) { + dolp = vp->value; + if (dolp == null) { switch (c) { case '=': if (isdigit(*s)) { @@ -4034,7 +3988,7 @@ static int dollar(int quoted) } } else if (c == '+') dolp = strsave(cp, areanum); - if (flag['u'] && dolp == null) { + if (FLAG['u'] && dolp == null) { prs("unset variable: "); err(s); gflg++; @@ -4050,12 +4004,13 @@ static int dollar(int quoted) static int grave(int quoted) { - char *cp; + /* moved to G: static char child_cmd[LINELIM]; */ + + const char *cp; int i; int j; int pf[2]; - static char child_cmd[LINELIM]; - char *src; + const char *src; char *dest; int count; int ignore; @@ -4068,11 +4023,12 @@ static int grave(int quoted) (void) &cp; #endif - for (cp = e.iop->argp->aword; *cp != '`'; cp++) + for (cp = e.iop->argp->aword; *cp != '`'; cp++) { if (*cp == 0) { err("no closing `"); return 0; } + } /* string copy with dollar expansion */ src = e.iop->argp->aword; @@ -4201,8 +4157,7 @@ static int grave(int quoted) e.iop->argp->aword = ++cp; close(pf[1]); PUSHIO(afile, remap(pf[0]), - (int (*)(struct ioarg *)) ((quoted) ? qgravechar : - gravechar)); + (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar)); return 1; } /* allow trapped signals */ @@ -4211,13 +4166,18 @@ 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] = "-c"; + argument_list[1] = (char *) "-c"; argument_list[2] = child_cmd; - argument_list[3] = 0; + argument_list[3] = NULL; cp = rexecve(argument_list[0], argument_list, makenv(1, wb)); prs(argument_list[0]); @@ -4231,7 +4191,8 @@ static char *unquote(char *as) { char *s; - if ((s = as) != NULL) + s = as; + if (s != NULL) while (*s) *s++ &= ~QUOTE; return as; @@ -4264,8 +4225,7 @@ static struct wdblock *glob(char *cp, struct wdblock *wb) else if (!any(*pp & ~QUOTE, spcl)) *pp &= ~QUOTE; if (i != 0) { - for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl); - cl = nl) { + for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) { nl = newword(cl->w_nword * 2); for (i = 0; i < cl->w_nword; i++) { /* for each argument */ for (pp = cl->w_words[i]; *pp; pp++) @@ -4325,7 +4285,7 @@ static void globname(char *we, char *pp) /* XXX Hmmm... What this could be? (abial) */ /* if (ent[j].d_ino == 0) - continue; + continue; */ strncpy(dname, de->d_name, NAME_MAX); if (dname[0] == '.') @@ -4360,8 +4320,7 @@ 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); + p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2); for (xp = start1; xp != end1;) *op++ = *xp++; for (xp = middle; (*op++ = *xp++) != '\0';); @@ -4387,6 +4346,7 @@ static int xstrcmp(char *p1, char *p2) return strcmp(*(char **) p1, *(char **) p2); } + /* -------- word.c -------- */ static struct wdblock *newword(int nw) @@ -4406,7 +4366,8 @@ static struct wdblock *addword(char *wd, struct wdblock *wb) if (wb == NULL) wb = newword(NSTART); - if ((nw = wb->w_nword) >= wb->w_bsize) { + nw = wb->w_nword; + if (nw >= wb->w_bsize) { wb2 = newword(nw * 2); memcpy((char *) wb2->w_words, (char *) wb->w_words, nw * sizeof(char *)); @@ -4418,8 +4379,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; @@ -4439,11 +4399,37 @@ char **getwords(struct wdblock *wb) static int (*func) (char *, char *); static int globv; -static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *)) +static void glob3(char *i, char *j, char *k) { - func = a3; - globv = a2; - glob1(a0, a0 + a1 * a2); + 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) @@ -4454,11 +4440,11 @@ static void glob1(char *base, char *lim) int c; unsigned n; - v2 = globv; - top: - if ((n = (int) (lim - base)) <= v2) + top: + n = (int) (lim - base); + if (n <= v2) return; n = v2 * (n / (2 * v2)); hptr = lptr = base + n; @@ -4466,8 +4452,10 @@ static void glob1(char *base, char *lim) j = lim - v2; for (;;) { if (i < lptr) { - if ((c = (*func) (i, lptr)) == 0) { - glob2(i, lptr -= v2); + c = (*func) (i, lptr); + if (c == 0) { + lptr -= v2; + glob2(i, lptr); continue; } if (c < 0) { @@ -4476,16 +4464,19 @@ static void glob1(char *base, char *lim) } } - begin: + begin: if (j > hptr) { - if ((c = (*func) (hptr, j)) == 0) { - glob2(hptr += v2, j); + c = (*func) (hptr, j); + if (c == 0) { + hptr += v2; + glob2(hptr, j); goto begin; } if (c > 0) { if (i == lptr) { - glob3(i, hptr += v2, j); - i = lptr += v2; + hptr += v2; + glob3(i, hptr, j); + i = (lptr += v2); goto begin; } glob2(i, j); @@ -4509,45 +4500,20 @@ static void glob1(char *base, char *lim) goto top; } - - glob3(j, lptr -= v2, i); - j = hptr -= v2; + lptr -= v2; + glob3(j, lptr, i); + j = (hptr -= v2); } } - -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 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 glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *)) +{ + func = a3; + globv = a2; + glob1(a0, a0 + a1 * a2); } + /* -------- io.c -------- */ /* @@ -4595,40 +4561,43 @@ static int readc(void) for (; e.iop >= e.iobase; e.iop--) { RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc)); - if ((c = e.iop->peekc) != '\0') { + c = e.iop->peekc; + if (c != '\0') { e.iop->peekc = 0; return c; - } else { - if (e.iop->prev != 0) { - if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') { - if (c == -1) { - e.iop++; - continue; - } - if (e.iop == iostack) - ioecho(c); - return (e.iop->prev = c); - } else if (e.iop->task == XIO && e.iop->prev != '\n') { - e.iop->prev = 0; - if (e.iop == iostack) - ioecho('\n'); - return '\n'; + } + if (e.iop->prev != 0) { + c = (*e.iop->iofn)(e.iop->argp, e.iop); + if (c != '\0') { + if (c == -1) { + e.iop++; + continue; } + if (e.iop == iostack) + ioecho(c); + e.iop->prev = c; + return e.iop->prev; } - if (e.iop->task == XIO) { - if (multiline) { - return e.iop->prev = 0; - } - if (interactive && e.iop == iostack + 1) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING - current_prompt = prompt->value; + if (e.iop->task == XIO && e.iop->prev != '\n') { + e.iop->prev = 0; + if (e.iop == iostack) + ioecho('\n'); + return '\n'; + } + } + if (e.iop->task == XIO) { + if (multiline) { + e.iop->prev = 0; + return e.iop->prev; + } + if (interactive && e.iop == iostack + 1) { +#if ENABLE_FEATURE_EDITING + current_prompt = prompt->value; #else - prs(prompt->value); + prs(prompt->value); #endif - } } } - } /* FOR */ if (e.iop >= iostack) { @@ -4645,7 +4614,7 @@ static int readc(void) static void ioecho(char c) { - if (flag['v']) + if (FLAG['v']) write(2, &c, sizeof c); } @@ -4707,12 +4676,10 @@ static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *)) if (fn == filechar || fn == linechar) e.iop->task = XIO; else if (fn == (int (*)(struct ioarg *)) gravechar - || fn == (int (*)(struct ioarg *)) qgravechar) + || fn == (int (*)(struct ioarg *)) qgravechar) e.iop->task = XGRAVE; else e.iop->task = XOTHER; - - return; } static struct io *setbase(struct io *ip) @@ -4737,7 +4704,8 @@ static int nlchar(struct ioarg *ap) if (ap->aword == NULL) return 0; - if ((c = *ap->aword++) == 0) { + c = *ap->aword++; + if (c == 0) { ap->aword = NULL; return '\n'; } @@ -4753,10 +4721,12 @@ static int wdchar(struct ioarg *ap) char c; char **wl; - if ((wl = ap->awordlist) == NULL) + wl = ap->awordlist; + if (wl == NULL) return 0; if (*wl != NULL) { - if ((c = *(*wl)++) != 0) + c = *(*wl)++; + if (c != 0) return c & 0177; ap->awordlist++; return ' '; @@ -4773,7 +4743,8 @@ static int dolchar(struct ioarg *ap) { char *wp; - if ((wp = *ap->awordlist++) != NULL) { + wp = *ap->awordlist++; + if (wp != NULL) { PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar); return -1; } @@ -4786,7 +4757,8 @@ static int xxchar(struct ioarg *ap) if (ap->aword == NULL) return 0; - if ((c = *ap->aword++) == '\0') { + c = *ap->aword++; + if (c == '\0') { ap->aword = NULL; return ' '; } @@ -4798,11 +4770,9 @@ static int xxchar(struct ioarg *ap) */ static int strchar(struct ioarg *ap) { - int c; - - if (ap->aword == NULL || (c = *ap->aword++) == 0) + if (ap->aword == NULL) return 0; - return c; + return *ap->aword++; } /* @@ -4812,9 +4782,12 @@ static int qstrchar(struct ioarg *ap) { int c; - if (ap->aword == NULL || (c = *ap->aword++) == 0) + if (ap->aword == NULL) return 0; - return c | QUOTE; + c = *ap->aword++; + if (c) + c |= QUOTE; + return c; } /* @@ -4827,45 +4800,42 @@ static int filechar(struct ioarg *ap) struct iobuf *bp = ap->afbuf; if (ap->afid != AFID_NOBUF) { - if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) { - + i = (ap->afid != bp->id); + if (i || bp->bufp == bp->ebufp) { if (i) lseek(ap->afile, ap->afpos, SEEK_SET); i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); - if (i <= 0) { closef(ap->afile); return 0; } bp->id = ap->afid; - bp->ebufp = (bp->bufp = bp->buf) + i; + bp->bufp = bp->buf; + bp->ebufp = bp->bufp + i; } ap->afpos++; return *bp->bufp++ & 0177; } -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_EDITING if (interactive && isatty(ap->afile)) { - static char mycommand[BUFSIZ]; + /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */ static int position = 0, size = 0; while (size == 0 || position >= size) { - cmdedit_read_input(current_prompt, mycommand); - size = strlen(mycommand); + read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state); + size = strlen(filechar_cmdbuf); position = 0; } - c = mycommand[position]; + c = filechar_cmdbuf[position]; position++; return c; - } else -#endif - - { - i = safe_read(ap->afile, &c, sizeof(c)); - return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); } +#endif + i = safe_read(ap->afile, &c, sizeof(c)); + return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); } /* @@ -4875,13 +4845,11 @@ static int herechar(struct ioarg *ap) { char c; - if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { close(ap->afile); - c = 0; + c = '\0'; } return c; - } /* @@ -4892,7 +4860,8 @@ static int gravechar(struct ioarg *ap, struct io *iop) { int c; - if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n') + c = qgravechar(ap, iop) & ~QUOTE; + if (c == '\n') c = ' '; return c; } @@ -4930,7 +4899,8 @@ static int linechar(struct ioarg *ap) { int c; - if ((c = filechar(ap)) == '\n') { + c = filechar(ap); + if (c == '\n') { if (!multiline) { closef(ap->afile); ap->afile = -1; /* illegal value */ @@ -4939,32 +4909,6 @@ static int linechar(struct ioarg *ap) return c; } -static void prs(const char *s) -{ - if (*s) - write(2, s, strlen(s)); -} - -static void prn(unsigned u) -{ - prs(itoa(u)); -} - -static void closef(int i) -{ - if (i > 2) - close(i); -} - -static void closeall(void) -{ - int u; - - for (u = NUFILE; u < NOFILE;) - close(u++); -} - - /* * remap fd into Shell's fd space */ @@ -4974,7 +4918,6 @@ static int remap(int fd) int map[NOFILE]; int newfd; - DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd)); if (fd < e.iofd) { @@ -5002,7 +4945,8 @@ static int openpipe(int *pv) { int i; - if ((i = pipe(pv)) < 0) + i = pipe(pv); + if (i < 0) err("can't create pipe - try again"); return i; } @@ -5015,6 +4959,7 @@ static void closepipe(int *pv) } } + /* -------- here.c -------- */ /* @@ -5028,7 +4973,7 @@ static void markhere(char *s, struct ioword *iop) DBGPRINTF7(("MARKHERE: enter, s=%p\n", s)); h = (struct here *) space(sizeof(struct here)); - if (h == 0) + if (h == NULL) return; h->h_tag = evalstr(s, DOSUB); @@ -5040,18 +4985,21 @@ static void markhere(char *s, struct ioword *iop) h->h_next = NULL; if (inhere == 0) inhere = h; - else - for (lh = inhere; lh != NULL; lh = lh->h_next) + else { + for (lh = inhere; lh != NULL; lh = lh->h_next) { if (lh->h_next == 0) { lh->h_next = h; break; } + } + } iop->io_flag |= IOHERE | IOXHERE; - for (s = h->h_tag; *s; s++) + for (s = h->h_tag; *s; s++) { if (*s & QUOTE) { iop->io_flag &= ~IOXHERE; *s &= ~QUOTE; } + } h->h_dosub = iop->io_flag & IOXHERE; } @@ -5089,14 +5037,15 @@ static void readhere(char **name, char *s, int ec) return; *name = strsave(tname, areanum); - if (newenv(setjmp(errpt = ev)) != 0) + errpt = ev; + if (newenv(setjmp(errpt)) != 0) unlink(tname); else { pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn); e.iobase = e.iop; for (;;) { if (interactive && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); @@ -5146,7 +5095,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; @@ -5158,7 +5107,8 @@ static int herein(char *hname, int xdoll) tf = mkstemp(tname); if (tf < 0) return -1; - if (newenv(setjmp(errpt = ev)) == 0) { + errpt = ev; + if (newenv(setjmp(errpt)) == 0) { PUSHIO(afile, hf, herechar); setbase(e.iop); while ((c = subgetc(0, 0)) != 0) { @@ -5169,11 +5119,11 @@ 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; - } else - return hf; + } + return hf; } static void scraphere(void) @@ -5210,6 +5160,218 @@ static void freehere(int area) } +/* -------- sh.c -------- */ +/* + * shell + */ + +int msh_main(int argc, char **argv); +int msh_main(int argc, char **argv) +{ + int f; + char *s; + int cflag; + char *name, **ap; + int (*iof) (struct ioarg *); + + PTR_TO_GLOBALS = xzalloc(sizeof(G)); + sharedbuf.id = AFID_NOBUF; + mainbuf.id = AFID_NOBUF; + e.linep = line; + elinep = line + sizeof(line) - 5; + +#if ENABLE_FEATURE_EDITING + line_input_state = new_line_input_t(FOR_SHELL); +#endif + + DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); + + initarea(); + ap = environ; + if (ap != NULL) { + while (*ap) + assign(*ap++, !COPYV); + for (ap = environ; *ap;) + export(lookup(*ap++)); + } + closeall(); + areanum = 1; + + shell = lookup("SHELL"); + if (shell->value == null) + setval(shell, (char *)DEFAULT_SHELL); + export(shell); + + homedir = lookup("HOME"); + if (homedir->value == null) + setval(homedir, "/"); + export(homedir); + + setval(lookup("$"), putn(getpid())); + + path = lookup("PATH"); + if (path->value == null) { + /* Can be merged with same string elsewhere in bbox */ + if (geteuid() == 0) + setval(path, "/sbin:/usr/sbin:/bin:/usr/bin"); + else + setval(path, "/sbin:/usr/sbin:/bin:/usr/bin" + sizeof("/sbin:/usr/sbin")); + } + export(path); + + ifs = lookup("IFS"); + if (ifs->value == null) + setval(ifs, " \t\n"); + +#ifdef MSHDEBUG + mshdbg_var = lookup("MSHDEBUG"); + if (mshdbg_var->value == null) + setval(mshdbg_var, "0"); +#endif + + prompt = lookup("PS1"); +#if ENABLE_FEATURE_EDITING_FANCY_PROMPT + if (prompt->value == null) +#endif + setval(prompt, DEFAULT_USER_PROMPT); + if (geteuid() == 0) { + setval(prompt, DEFAULT_ROOT_PROMPT); + prompt->status &= ~EXPORT; + } + cprompt = lookup("PS2"); +#if ENABLE_FEATURE_EDITING_FANCY_PROMPT + if (cprompt->value == null) +#endif + setval(cprompt, "> "); + + iof = filechar; + cflag = 0; + name = *argv++; + if (--argc >= 1) { + if (argv[0][0] == '-' && argv[0][1] != '\0') { + for (s = argv[0] + 1; *s; s++) + switch (*s) { + case 'c': + prompt->status &= ~EXPORT; + cprompt->status &= ~EXPORT; + setval(prompt, ""); + setval(cprompt, ""); + cflag = 1; + if (--argc > 0) + PUSHIO(aword, *++argv, iof = nlchar); + break; + + case 'q': + qflag = SIG_DFL; + break; + + case 's': + /* standard input */ + break; + + case 't': + prompt->status &= ~EXPORT; + setval(prompt, ""); + iof = linechar; + break; + + case 'i': + interactive++; + default: + if (*s >= 'a' && *s <= 'z') + FLAG[(int) *s]++; + } + } else { + argv--; + argc++; + } + + if (iof == filechar && --argc > 0) { + setval(prompt, ""); + setval(cprompt, ""); + prompt->status &= ~EXPORT; + cprompt->status &= ~EXPORT; + +/* Shell is non-interactive, activate printf-based debug */ +#ifdef MSHDEBUG + mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0'); + if (mshdbg < 0) + mshdbg = 0; +#endif + DBGPRINTF(("MSH_MAIN: calling newfile()\n")); + + name = *++argv; + if (newfile(name)) + exit(1); /* Exit on error */ + } + } + + setdash(); + + /* This won't be true if PUSHIO has been called, say from newfile() above */ + if (e.iop < iostack) { + PUSHIO(afile, 0, iof); + if (isatty(0) && isatty(1) && !cflag) { + interactive++; +#if !ENABLE_FEATURE_SH_EXTRA_QUIET +#ifdef MSHDEBUG + 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); +#endif + printf("Enter 'help' for a list of built-in commands.\n\n"); +#endif + } + } + + signal(SIGQUIT, qflag); + if (name && name[0] == '-') { + interactive++; + f = open(".profile", O_RDONLY); + if (f >= 0) + next(remap(f)); + f = open("/etc/profile", O_RDONLY); + if (f >= 0) + next(remap(f)); + } + if (interactive) + signal(SIGTERM, sig); + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); + 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)); + + for (;;) { + if (interactive && e.iop <= iostack) { +#if ENABLE_FEATURE_EDITING + current_prompt = prompt->value; +#else + prs(prompt->value); +#endif + } + onecommand(); + /* Ensure that getenv("PATH") stays current */ + setenv("PATH", path->value, 1); + } + + DBGPRINTF(("MSH_MAIN: returning.\n")); +} + /* * Copyright (c) 1987,1997, Prentice Hall