X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fhush.c;h=1eff182efaf23599af42d0ddd3fb06af16ba1a2d;hb=784ab7c545d25288a82216d18e2b0ca3beae470b;hp=925474332be99bf901efbf8c148e69a3fa6fc2e3;hpb=c7de829c796978e519984df2f1c8cfcf921a39a4;p=u-boot diff --git a/common/hush.c b/common/hush.c index 925474332b..1eff182efa 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1,4 +1,3 @@ -/* vi: set sw=4 ts=4: */ /* * sh.c -- a prototype Bourne shell grammar parser * Intended to follow the original Thompson and Ritchie @@ -18,7 +17,6 @@ * Erik W. Troan, which they placed in the public domain. I don't know * how much of the Johnson/Troan code has survived the repeated rewrites. * Other credits: - * simple_itoa() was lifted from boa-0.93.15 * b_addchr() derived from similar w_addchar function in glibc-2.2 * setup_redirect(), redirect_opt_num(), and big chunks of main() * and many builtins derived from contributions by Erik Andersen @@ -94,9 +92,10 @@ #include /* readline */ #include #include /* find_cmd */ -#include /* do_bootd */ +#ifndef CONFIG_SYS_PROMPT_HUSH_PS2 +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " +#endif #endif -#ifdef CFG_HUSH_PARSER #ifndef __U_BOOT__ #include /* isalpha, isdigit */ #include /* getpid */ @@ -115,16 +114,16 @@ #include /* #include */ -/* #define DEBUG_SHELL */ -#ifdef BB_VER +#if 1 #include "busybox.h" #include "cmdedit.h" #else #define applet_name "hush" #include "standalone.h" #define hush_main main -#undef BB_FEATURE_SH_FANCY_PROMPT +#undef CONFIG_FEATURE_SH_FANCY_PROMPT +#define BB_BANNER #endif #endif #define SPECIAL_VAR_SYMBOL 03 @@ -136,6 +135,8 @@ #endif #ifdef __U_BOOT__ +DECLARE_GLOBAL_DATA_PTR; + #define EXIT_SUCCESS 0 #define EOF -1 #define syntax() syntax_err() @@ -288,12 +289,13 @@ char **global_argv; unsigned int global_argc; #endif unsigned int last_return_code; +int nesting_level; #ifndef __U_BOOT__ extern char **environ; /* This is in , but protected with __USE_GNU */ #endif /* "globals" within this file */ -static char *ifs; +static uchar *ifs; static char map[256]; #ifndef __U_BOOT__ static int fake_mode; @@ -311,7 +313,7 @@ struct variables *top_vars = &shell_ver; #else static int flag_repeat = 0; static int do_repeat = 0; -static struct variables *top_vars ; +static struct variables *top_vars = NULL ; #endif /*__U_BOOT__ */ #define B_CHUNK (100) @@ -356,6 +358,11 @@ struct built_in_command { }; #endif +/* define DEBUG_SHELL for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG_SHELL +#endif + /* This should be in utility.c */ #ifdef DEBUG_SHELL #ifndef __U_BOOT__ @@ -367,7 +374,7 @@ static void debug_printf(const char *format, ...) va_end(args); } #else -#define debug_printf printf /* U-Boot debug flag */ +#define debug_printf(fmt,args...) printf (fmt ,##args) #endif #else static inline void debug_printf(const char *format, ...) { } @@ -414,7 +421,9 @@ static int b_check_space(o_string *o, int len); static int b_addchr(o_string *o, int ch); static void b_reset(o_string *o); static int b_addqchr(o_string *o, int ch, int quote); +#ifndef __U_BOOT__ static int b_adduint(o_string *o, unsigned int i); +#endif /* in_str manipulations: */ static int static_get(struct in_str *i); static int static_peek(struct in_str *i); @@ -430,7 +439,7 @@ static void setup_string_in_str(struct in_str *i, const char *s); /* close_me manipulations: */ static void mark_open(int fd); static void mark_closed(int fd); -static void close_all(); +static void close_all(void); #endif /* "run" the final data structures: */ static char *indenter(int i); @@ -490,11 +499,6 @@ static void remove_bg_job(struct pipe *pi); /* local variable support */ static char **make_list_in(char **inp, char *name); static char *insert_var_value(char *inp); -static char *get_local_var(const char *var); -#ifndef __U_BOOT__ -static void unset_local_var(const char *name); -#endif -static int set_local_var(const char *s, int flg_export); #ifndef __U_BOOT__ /* Table of built-in functions. They can be forked or not, depending on @@ -902,7 +906,7 @@ static void b_reset(o_string *o) static void b_free(o_string *o) { b_reset(o); - if (o->data != NULL) free(o->data); + free(o->data); o->data = NULL; o->maxlen = 0; } @@ -920,20 +924,7 @@ static int b_addqchr(o_string *o, int ch, int quote) return b_addchr(o, ch); } -/* belongs in utility.c */ -char *simple_itoa(unsigned int i) -{ - /* 21 digits plus null terminator, good for 64-bit or smaller ints */ - static char local[22]; - char *p = &local[21]; - *p-- = '\0'; - do { - *p-- = '0' + i % 10; - i /= 10; - } while (i > 0); - return p + 1; -} - +#ifndef __U_BOOT__ static int b_adduint(o_string *o, unsigned int i) { int r; @@ -942,10 +933,11 @@ static int b_adduint(o_string *o, unsigned int i) do r=b_addchr(o, *p++); while (r==0 && *p); return r; } +#endif static int static_get(struct in_str *i) { - int ch=*i->p++; + int ch = *i->p++; if (ch=='\0') return EOF; return ch; } @@ -958,7 +950,7 @@ static int static_peek(struct in_str *i) #ifndef __U_BOOT__ static inline void cmdedit_set_initial_prompt(void) { -#ifndef BB_FEATURE_SH_FANCY_PROMPT +#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT PS1 = NULL; #else PS1 = getenv("PS1"); @@ -970,11 +962,10 @@ static inline void cmdedit_set_initial_prompt(void) static inline void setup_prompt_string(int promptmode, char **prompt_str) { debug_printf("setup_prompt_string %d ",promptmode); -#ifndef BB_FEATURE_SH_FANCY_PROMPT +#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT /* Set up the prompt */ if (promptmode == 1) { - if (PS1) - free(PS1); + free(PS1); PS1=xmalloc(strlen(cwd)+4); sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); *prompt_str = PS1; @@ -995,7 +986,7 @@ static void get_user_input(struct in_str *i) static char the_command[BUFSIZ]; setup_prompt_string(i->promptmode, &prompt_str); -#ifdef BB_FEATURE_COMMAND_EDITING +#ifdef CONFIG_FEATURE_COMMAND_EDITING /* ** enable command line editing only while a command line ** is actually being read; otherwise, we'll end up bequeathing @@ -1012,16 +1003,31 @@ static void get_user_input(struct in_str *i) fflush(stdout); i->p = the_command; #else - extern char console_buffer[CFG_CBSIZE]; int n; - static char the_command[CFG_CBSIZE]; + static char the_command[CONFIG_SYS_CBSIZE]; +#ifdef CONFIG_BOOT_RETRY_TIME +# ifndef CONFIG_RESET_TO_RETRY +# error "This currently only works with CONFIG_RESET_TO_RETRY enabled" +# endif + reset_cmd_timeout(); +#endif i->__promptme = 1; if (i->promptmode == 1) { - n = readline(CFG_PROMPT); + n = readline(CONFIG_SYS_PROMPT); } else { - n = readline(CFG_PROMPT_HUSH_PS2); + n = readline(CONFIG_SYS_PROMPT_HUSH_PS2); + } +#ifdef CONFIG_BOOT_RETRY_TIME + if (n == -2) { + puts("\nTimeout waiting for command\n"); +# ifdef CONFIG_RESET_TO_RETRY + do_reset(NULL, 0, 0, NULL); +# else +# error "This currently only works with CONFIG_RESET_TO_RETRY enabled" +# endif } +#endif if (n == -1 ) { flag_repeat = 0; i->__promptme = 0; @@ -1048,12 +1054,12 @@ static void get_user_input(struct in_str *i) i->p = the_command; } else { - if (console_buffer[0] != '\n') { - if (strlen(the_command) + strlen(console_buffer) - < CFG_CBSIZE) { - n = strlen(the_command); - the_command[n-1] = ' '; - strcpy(&the_command[n],console_buffer); + if (console_buffer[0] != '\n') { + if (strlen(the_command) + strlen(console_buffer) + < CONFIG_SYS_CBSIZE) { + n = strlen(the_command); + the_command[n-1] = ' '; + strcpy(&the_command[n],console_buffer); } else { the_command[0] = '\n'; @@ -1079,7 +1085,7 @@ static int file_get(struct in_str *i) ch = 0; /* If there is data waiting, eat it up */ if (i->p && *i->p) { - ch=*i->p++; + ch = *i->p++; } else { /* need to double check i->file because we might be doing something * more complicated by now, like sourcing or substituting. */ @@ -1096,7 +1102,7 @@ static int file_get(struct in_str *i) i->__promptme = 0; #endif if (i->p && *i->p) { - ch=*i->p++; + ch = *i->p++; } #ifndef __U_BOOT__ } else { @@ -1176,7 +1182,7 @@ static void mark_closed(int fd) free(tmp); } -static void close_all() +static void close_all(void) { struct close_me *c; for (c=close_me_head; c; c=c->next) { @@ -1257,8 +1263,8 @@ static void pseudo_exec(struct child_prog *child) if (p != child->argv[i]) free(p); } child->argv+=i; /* XXX this hack isn't so horrible, since we are about - to exit, and therefore don't need to keep data - structures consistent for free() use. */ + to exit, and therefore don't need to keep data + structures consistent for free() use. */ /* If a variable is assigned in a forest, and nobody listens, * was it ever really set? */ @@ -1290,18 +1296,18 @@ static void pseudo_exec(struct child_prog *child) * really dislike relying on /proc for things. We could exec ourself * from global_argv[0], but if we are in a chroot, we may not be able * to find ourself... */ -#ifdef BB_FEATURE_SH_STANDALONE_SHELL +#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL { int argc_l; char** argv_l=child->argv; char *name = child->argv[0]; -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN +#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN /* Following discussions from November 2000 on the busybox mailing * list, the default configuration, (without * get_last_path_component()) lets the user force use of an * external command by specifying the full (with slashes) filename. - * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets + * If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN then applets * _aways_ override external commands, so if you want to run * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the * filesystem and is _not_ busybox. Some systems may want this, @@ -1524,13 +1530,25 @@ static int run_pipe_real(struct pipe *pi) struct child_prog *child; struct built_in_command *x; char *p; +# if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &i; + (void) &nextin; + (void) &nextout; + (void) &child; +# endif #else int nextin; int flag = do_repeat ? CMD_FLAG_REPEAT : 0; struct child_prog *child; - cmd_tbl_t *cmdtp; char *p; -#endif +# if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &i; + (void) &nextin; + (void) &child; +# endif +#endif /* __U_BOOT__ */ nextin = 0; #ifndef __U_BOOT__ @@ -1626,57 +1644,30 @@ static int run_pipe_real(struct pipe *pi) * Is it really safe for inline use? Experimentally, * things seem to work with glibc. */ setup_redirects(child, squirrel); -#else - /* check ";", because ,example , argv consist from - * "help;flinfo" must not execute - */ - if (strchr(child->argv[i], ';')) { - printf ("Unknown command '%s' - try 'help' or use 'run' command\n", - child->argv[i]); - return -1; - } - /* Look up command in command table */ - if ((cmdtp = find_cmd(child->argv[i])) == NULL) { - printf ("Unknown command '%s' - try 'help'\n", child->argv[i]); - return -1; /* give up after bad command */ - } else { - int rcode; -#if (CONFIG_COMMANDS & CFG_CMD_BOOTD) - /* avoid "bootd" recursion */ - if (cmdtp->cmd == do_bootd) { - if (flag & CMD_FLAG_BOOTD) { - printf ("'bootd' recursion detected\n"); - return -1; - } - else - flag |= CMD_FLAG_BOOTD; - } -#endif /* CFG_CMD_BOOTD */ - /* found - check max args */ - if ((child->argc - i) > cmdtp->maxargs) { - printf ("Usage:\n%s\n", cmdtp->usage); - return -1; - } -#endif - child->argv+=i; /* XXX horrible hack */ -#ifndef __U_BOOT__ + + child->argv += i; /* XXX horrible hack */ rcode = x->function(child); -#else - /* OK - call function to do the command */ - rcode = (cmdtp->cmd) - (cmdtp, flag,child->argc-i,&child->argv[i]); - if ( !cmdtp->repeatable ) - flag_repeat = 0; -#endif - child->argv-=i; /* XXX restore hack so free() can work right */ -#ifndef __U_BOOT__ + /* XXX restore hack so free() can work right */ + child->argv -= i; restore_redirects(squirrel); -#endif - return rcode; } + return rcode; } -#ifndef __U_BOOT__ +#else + /* check ";", because ,example , argv consist from + * "help;flinfo" must not execute + */ + if (strchr(child->argv[i], ';')) { + printf("Unknown command '%s' - try 'help' or use " + "'run' command\n", child->argv[i]); + return -1; + } + /* Process the command */ + return cmd_process(flag, child->argc, child->argv, + &flag_repeat); +#endif } +#ifndef __U_BOOT__ for (i = 0; i < pi->num_progs; i++) { child = & (pi->progs[i]); @@ -1820,7 +1811,7 @@ static int run_list_real(struct pipe *pi) if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; if (rmode == RES_THEN && if_code) continue; if (rmode == RES_ELSE && !if_code) continue; - if (rmode == RES_ELIF && !if_code) continue; + if (rmode == RES_ELIF && !if_code) break; if (rmode == RES_FOR && pi->num_progs) { if (!list) { /* if no variable values after "in" we skip "for" */ @@ -1898,6 +1889,10 @@ static int run_list_real(struct pipe *pi) } last_return_code=rcode; #else + if (rcode < -1) { + last_return_code = -rcode - 2; + return -2; /* exit */ + } last_return_code=(rcode == 0) ? 0 : 1; #endif #ifndef __U_BOOT__ @@ -1952,11 +1947,11 @@ static int free_pipe(struct pipe *pi, int indent) #ifndef __U_BOOT__ globfree(&child->glob_result); #else - for (a = child->argc;a >= 0;a--) { - free(child->argv[a]); - } + for (a = 0; a < child->argc; a++) { + free(child->argv[a]); + } free(child->argv); - child->argc = 0; + child->argc = 0; #endif child->argv=NULL; } else if (child->group) { @@ -2090,17 +2085,17 @@ static int xglob(o_string *dest, int flags, glob_t *pglob) { int gr; - /* short-circuit for null word */ + /* short-circuit for null word */ /* we can code this better when the debug_printf's are gone */ - if (dest->length == 0) { - if (dest->nonnull) { - /* bash man page calls this an "explicit" null */ - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } else { + if (dest->length == 0) { + if (dest->nonnull) { + /* bash man page calls this an "explicit" null */ + gr = globhack(dest->data, flags, pglob); + debug_printf("globhack returned %d\n",gr); + } else { return 0; } - } else if (glob_needed(dest->data)) { + } else if (glob_needed(dest->data)) { gr = glob(dest->data, flags, NULL, pglob); debug_printf("glob returned %d\n",gr); if (gr == GLOB_NOMATCH) { @@ -2122,13 +2117,23 @@ static int xglob(o_string *dest, int flags, glob_t *pglob) } #endif +#ifdef __U_BOOT__ +static char *get_dollar_var(char ch); +#endif + /* This is used to get/check local shell variables */ -static char *get_local_var(const char *s) +char *get_local_var(const char *s) { struct variables *cur; if (!s) return NULL; + +#ifdef __U_BOOT__ + if (*s == '$') + return get_dollar_var(s[1]); +#endif + for (cur = top_vars; cur; cur=cur->next) if(strcmp(cur->name, s)==0) return cur->value; @@ -2139,18 +2144,25 @@ static char *get_local_var(const char *s) flg_export==0 if only local (not exporting) variable flg_export==1 if "new" exporting environ flg_export>1 if current startup environ (not call putenv()) */ -static int set_local_var(const char *s, int flg_export) +int set_local_var(const char *s, int flg_export) { char *name, *value; int result=0; struct variables *cur; +#ifdef __U_BOOT__ + /* might be possible! */ + if (!isalpha(*s)) + return -1; +#endif + name=strdup(s); #ifdef __U_BOOT__ if (getenv(name) != NULL) { printf ("ERROR: " - "There is a global environmet variable with the same name.\n"); + "There is a global environment variable with the same name.\n"); + free(name); return -1; } #endif @@ -2223,8 +2235,7 @@ static int set_local_var(const char *s, int flg_export) return result; } -#ifndef __U_BOOT__ -static void unset_local_var(const char *name) +void unset_local_var(const char *name) { struct variables *cur; @@ -2239,8 +2250,10 @@ static void unset_local_var(const char *name) error_msg("%s: readonly variable", name); return; } else { +#ifndef __U_BOOT__ if(cur->flg_export) unsetenv(cur->name); +#endif free(cur->name); free(cur->value); while (next->next != cur) @@ -2251,11 +2264,13 @@ static void unset_local_var(const char *name) } } } -#endif static int is_assignment(const char *s) { - if (s==NULL || !isalpha(*s)) return 0; + if (s == NULL) + return 0; + + if (!isalpha(*s)) return 0; ++s; while(isalnum(*s) || *s=='_') ++s; return *s=='='; @@ -2319,6 +2334,7 @@ struct pipe *new_pipe(void) { pi->progs = NULL; pi->next = NULL; pi->followup = 0; /* invalid */ + pi->r_mode = RES_NONE; return pi; } @@ -2344,34 +2360,35 @@ static void initialize_context(struct p_context *ctx) * should handle if, then, elif, else, fi, for, while, until, do, done. * case, function, and select are obnoxious, save those for later. */ +struct reserved_combo { + char *literal; + int code; + long flag; +}; +/* Mostly a list of accepted follow-up reserved words. + * FLAG_END means we are done with the sequence, and are ready + * to turn the compound list into a command. + * FLAG_START means the word must start a new compound list. + */ +static struct reserved_combo reserved_list[] = { + { "if", RES_IF, FLAG_THEN | FLAG_START }, + { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, + { "elif", RES_ELIF, FLAG_THEN }, + { "else", RES_ELSE, FLAG_FI }, + { "fi", RES_FI, FLAG_END }, + { "for", RES_FOR, FLAG_IN | FLAG_START }, + { "while", RES_WHILE, FLAG_DO | FLAG_START }, + { "until", RES_UNTIL, FLAG_DO | FLAG_START }, + { "in", RES_IN, FLAG_DO }, + { "do", RES_DO, FLAG_DONE }, + { "done", RES_DONE, FLAG_END } +}; +#define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo)) + int reserved_word(o_string *dest, struct p_context *ctx) { - struct reserved_combo { - char *literal; - int code; - long flag; - }; - /* Mostly a list of accepted follow-up reserved words. - * FLAG_END means we are done with the sequence, and are ready - * to turn the compound list into a command. - * FLAG_START means the word must start a new compound list. - */ - static struct reserved_combo reserved_list[] = { - { "if", RES_IF, FLAG_THEN | FLAG_START }, - { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, - { "elif", RES_ELIF, FLAG_THEN }, - { "else", RES_ELSE, FLAG_FI }, - { "fi", RES_FI, FLAG_END }, - { "for", RES_FOR, FLAG_IN | FLAG_START }, - { "while", RES_WHILE, FLAG_DO | FLAG_START }, - { "until", RES_UNTIL, FLAG_DO | FLAG_START }, - { "in", RES_IN, FLAG_DO }, - { "do", RES_DO, FLAG_DONE }, - { "done", RES_DONE, FLAG_END } - }; struct reserved_combo *r; for (r=reserved_list; -#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) rdata, r->literal) == 0) { debug_printf("found reserved word %s, code %d\n",r->literal,r->code); @@ -2448,7 +2465,7 @@ static int done_word(o_string *dest, struct p_context *ctx) } #ifndef __U_BOOT__ glob_target = &child->glob_result; - if (child->argv) flags |= GLOB_APPEND; + if (child->argv) flags |= GLOB_APPEND; #else for (cnt = 1, s = dest->data; s && *s; s++) { if (*s == '\\') s++; @@ -2508,9 +2525,9 @@ static int done_command(struct p_context *ctx) struct child_prog *prog=ctx->child; if (prog && prog->group == NULL - && prog->argv == NULL + && prog->argv == NULL #ifndef __U_BOOT__ - && prog->redirects == NULL) { + && prog->redirects == NULL) { #else ) { #endif @@ -2725,15 +2742,35 @@ static int parse_group(o_string *dest, struct p_context *ctx, * see the bash man page under "Parameter Expansion" */ static char *lookup_param(char *src) { - char *p=NULL; - if (src) { + char *p; + + if (!src) + return NULL; + p = getenv(src); if (!p) p = get_local_var(src); - } + return p; } +#ifdef __U_BOOT__ +static char *get_dollar_var(char ch) +{ + static char buf[40]; + + buf[0] = '\0'; + switch (ch) { + case '?': + sprintf(buf, "%u", (unsigned int)last_return_code); + break; + default: + return NULL; + } + return buf; +} +#endif + /* return code: 0 for OK, 1 for syntax error */ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) { @@ -2775,7 +2812,15 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i break; #endif case '?': +#ifndef __U_BOOT__ b_adduint(dest,last_return_code); +#else + ctx->child->sp++; + b_addchr(dest, SPECIAL_VAR_SYMBOL); + b_addchr(dest, '$'); + b_addchr(dest, '?'); + b_addchr(dest, SPECIAL_VAR_SYMBOL); +#endif advance = 1; break; #ifndef __U_BOOT__ @@ -2861,8 +2906,11 @@ int parse_stream(o_string *dest, struct p_context *ctx, if (input->__promptme == 0) return 1; #endif next = (ch == '\n') ? 0 : b_peek(input); - debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", - ch,ch,m,dest->quote); + + debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n", + ch >= ' ' ? ch : '.', ch, m, + dest->quote, ctx->stack == NULL ? '*' : '.'); + if (m==0 || ((m==1 || m==2) && dest->quote)) { b_addqchr(dest, ch, dest->quote); } else { @@ -3031,8 +3079,8 @@ void mapset(const unsigned char *set, int code) void update_ifs_map(void) { /* char *ifs and char map[256] are both globals. */ - ifs = getenv("IFS"); - if (ifs == NULL) ifs=" \t\n"; + ifs = (uchar *)getenv("IFS"); + if (ifs == NULL) ifs=(uchar *)" \t\n"; /* Precompute a list of 'flow through' behavior so it can be treated * quickly up front. Computation is necessary because of IFS. * Special case handling of IFS == " \t\n" is not implemented. @@ -3041,11 +3089,11 @@ void update_ifs_map(void) */ memset(map,0,sizeof(map)); /* most characters flow through always */ #ifndef __U_BOOT__ - mapset("\\$'\"`", 3); /* never flow through */ - mapset("<>;&|(){}#", 1); /* flow through if quoted */ + mapset((uchar *)"\\$'\"`", 3); /* never flow through */ + mapset((uchar *)"<>;&|(){}#", 1); /* flow through if quoted */ #else - mapset("\\$'\"", 3); /* never flow through */ - mapset(";&|#", 1); /* flow through if quoted */ + mapset((uchar *)"\\$'\"", 3); /* never flow through */ + mapset((uchar *)";&|#", 1); /* flow through if quoted */ #endif mapset(ifs, 2); /* also flow through if quoted */ } @@ -3065,7 +3113,7 @@ int parse_stream_outer(struct in_str *inp, int flag) ctx.type = flag; initialize_context(&ctx); update_ifs_map(); - if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0); + if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset((uchar *)";$&|", 0); inp->promptmode=1; rcode = parse_stream(&temp, &ctx, inp, '\n'); #ifdef __U_BOOT__ @@ -3083,7 +3131,18 @@ int parse_stream_outer(struct in_str *inp, int flag) #ifndef __U_BOOT__ run_list(ctx.list_head); #else - if (((code = run_list(ctx.list_head)) == -1)) + code = run_list(ctx.list_head); + if (code == -2) { /* exit */ + b_free(&temp); + code = 0; + /* XXX hackish way to not allow exit from main loop */ + if (inp->peek == file_peek) { + printf("exit not allowed from main input shell.\n"); + continue; + } + break; + } + if (code == -1) flag_repeat = 0; #endif } else { @@ -3112,7 +3171,7 @@ int parse_stream_outer(struct in_str *inp, int flag) #ifndef __U_BOOT__ static int parse_string_outer(const char *s, int flag) #else -int parse_string_outer(char *s, int flag) +int parse_string_outer(const char *s, int flag) #endif /* __U_BOOT__ */ { struct in_str input; @@ -3156,14 +3215,32 @@ int parse_file_outer(void) } #ifdef __U_BOOT__ +#ifdef CONFIG_NEEDS_MANUAL_RELOC +static void u_boot_hush_reloc(void) +{ + unsigned long addr; + struct reserved_combo *r; + + for (r=reserved_list; rliteral) + gd->reloc_off; + r->literal = (char *)addr; + } +} +#endif + int u_boot_hush_start(void) { - top_vars = malloc(sizeof(struct variables)); - top_vars->name = "HUSH_VERSION"; - top_vars->value = "0.01"; - top_vars->next = 0; - top_vars->flg_export = 0; - top_vars->flg_read_only = 1; + if (top_vars == NULL) { + top_vars = malloc(sizeof(struct variables)); + top_vars->name = "HUSH_VERSION"; + top_vars->value = "0.01"; + top_vars->next = 0; + top_vars->flg_export = 0; + top_vars->flg_read_only = 1; +#ifdef CONFIG_NEEDS_MANUAL_RELOC + u_boot_hush_reloc(); +#endif + } return 0; } @@ -3194,7 +3271,7 @@ static void *xrealloc(void *ptr, size_t size) /* Make sure we have a controlling tty. If we get started under a job * aware app (like bash for example), make sure we are now in charge so * we don't fight over who gets the foreground */ -static void setup_job_control() +static void setup_job_control(void) { static pid_t shell_pgrp; /* Loop until we are in the foreground. */ @@ -3219,7 +3296,7 @@ static void setup_job_control() tcsetpgrp(shell_terminal, shell_pgrp); } -int hush_main(int argc, char **argv) +int hush_main(int argc, char * const *argv) { int opt; FILE *input; @@ -3243,7 +3320,7 @@ int hush_main(int argc, char **argv) /* Initialize some more globals to non-zero values */ set_cwd(); -#ifdef BB_FEATURE_COMMAND_EDITING +#ifdef CONFIG_FEATURE_COMMAND_EDITING cmdedit_set_initial_prompt(); #else PS1 = NULL; @@ -3312,7 +3389,10 @@ int hush_main(int argc, char **argv) debug_printf("\ninteractive=%d\n", interactive); if (interactive) { /* Looks like they want an interactive shell */ - fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); +#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET + printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n"); + printf( "Enter 'help' for a list of built-in commands.\n\n"); +#endif setup_job_control(); } @@ -3327,7 +3407,7 @@ int hush_main(int argc, char **argv) input = xfopen(argv[optind], "r"); opt = parse_file_outer(input); -#ifdef BB_FEATURE_CLEAN_UP +#ifdef CONFIG_FEATURE_CLEAN_UP fclose(input); if (cwd && cwd != unknown) free((char*)cwd); @@ -3452,5 +3532,52 @@ static char * make_string(char ** inp) return str; } -#endif /* CFG_HUSH_PARSER */ +#ifdef __U_BOOT__ +int do_showvar (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int i, k; + int rcode = 0; + struct variables *cur; + + if (argc == 1) { /* Print all env variables */ + for (cur = top_vars; cur; cur = cur->next) { + printf ("%s=%s\n", cur->name, cur->value); + if (ctrlc ()) { + puts ("\n ** Abort\n"); + return 1; + } + } + return 0; + } + for (i = 1; i < argc; ++i) { /* print single env variables */ + char *name = argv[i]; + + k = -1; + for (cur = top_vars; cur; cur = cur->next) { + if(strcmp (cur->name, name) == 0) { + k = 0; + printf ("%s=%s\n", cur->name, cur->value); + } + if (ctrlc ()) { + puts ("\n ** Abort\n"); + return 1; + } + } + if (k < 0) { + printf ("## Error: \"%s\" not defined\n", name); + rcode ++; + } + } + return rcode; +} + +U_BOOT_CMD( + showvar, CONFIG_SYS_MAXARGS, 1, do_showvar, + "print local hushshell variables", + "\n - print values of all hushshell variables\n" + "showvar name ...\n" + " - print value of hushshell variable 'name'" +); + +#endif /****************************************************************************/