X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fhush.c;h=75c18ce8ae0b58d9273916842ecc78caa9f1e5ac;hb=ebb86c4ecd37a7701358284e497ca4c6483c7cc5;hp=3cb6fc3b1cb18f020f12b85ff1639f6e805d5899;hpb=fe8c2806cdba70479e351299881a395dc2be7785;p=u-boot diff --git a/common/hush.c b/common/hush.c index 3cb6fc3b1c..75c18ce8ae 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 @@ -94,7 +93,8 @@ #include /* readline */ #include #include /* find_cmd */ -#include /* do_bootd */ +/*cmd_boot.c*/ +extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* do_bootd */ #endif #ifdef CFG_HUSH_PARSER #ifndef __U_BOOT__ @@ -117,14 +117,15 @@ /* #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 +137,8 @@ #endif #ifdef __U_BOOT__ +DECLARE_GLOBAL_DATA_PTR; + #define EXIT_SUCCESS 0 #define EOF -1 #define syntax() syntax_err() @@ -288,12 +291,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 +315,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,11 +360,6 @@ struct built_in_command { }; #endif -/* belongs in busybox.h */ -static inline int max(int a, int b) { - return (a>b)?a:b; -} - /* This should be in utility.c */ #ifdef DEBUG_SHELL #ifndef __U_BOOT__ @@ -419,7 +418,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); @@ -435,7 +436,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); @@ -907,7 +908,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; } @@ -939,6 +940,7 @@ char *simple_itoa(unsigned int i) return p + 1; } +#ifndef __U_BOOT__ static int b_adduint(o_string *o, unsigned int i) { int r; @@ -947,10 +949,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; } @@ -963,7 +966,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"); @@ -975,11 +978,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; @@ -1000,7 +1002,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 @@ -1021,12 +1023,30 @@ static void get_user_input(struct in_str *i) int n; static char the_command[CFG_CBSIZE]; +#ifdef CONFIG_BOOT_RETRY_TIME +# ifdef CONFIG_RESET_TO_RETRY + extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +# else +# 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); } else { n = readline(CFG_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; @@ -1053,12 +1073,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) + 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); + n = strlen(the_command); + the_command[n-1] = ' '; + strcpy(&the_command[n],console_buffer); } else { the_command[0] = '\n'; @@ -1084,7 +1104,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. */ @@ -1101,7 +1121,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 { @@ -1181,7 +1201,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) { @@ -1262,8 +1282,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? */ @@ -1295,18 +1315,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, @@ -1529,13 +1549,26 @@ 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__ @@ -1640,14 +1673,18 @@ static int run_pipe_real(struct pipe *pi) child->argv[i]); return -1; } - /* Look up command in command table */ + /* 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 defined(CONFIG_CMD_BOOTD) + extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); + + /* avoid "bootd" recursion */ if (cmdtp->cmd == do_bootd) { if (flag & CMD_FLAG_BOOTD) { printf ("'bootd' recursion detected\n"); @@ -1656,8 +1693,8 @@ static int run_pipe_real(struct pipe *pi) else flag |= CMD_FLAG_BOOTD; } -#endif /* CFG_CMD_BOOTD */ - /* found - check max args */ +#endif + /* found - check max args */ if ((child->argc - i) > cmdtp->maxargs) { printf ("Usage:\n%s\n", cmdtp->usage); return -1; @@ -1668,15 +1705,20 @@ static int run_pipe_real(struct pipe *pi) rcode = x->function(child); #else /* OK - call function to do the command */ + rcode = (cmdtp->cmd) - (cmdtp, flag,child->argc-i,&child->argv[i]); +(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__ + restore_redirects(squirrel); #endif + return rcode; } } @@ -1825,7 +1867,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" */ @@ -1903,6 +1945,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__ @@ -1957,11 +2003,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 = child->argc;a >= 0;a--) { + free(child->argv[a]); + } free(child->argv); - child->argc = 0; + child->argc = 0; #endif child->argv=NULL; } else if (child->group) { @@ -2095,17 +2141,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) { @@ -2127,6 +2173,10 @@ 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) { @@ -2134,6 +2184,12 @@ static char *get_local_var(const char *s) 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; @@ -2150,12 +2206,19 @@ static int set_local_var(const char *s, int flg_export) 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 @@ -2260,7 +2323,10 @@ static void unset_local_var(const char *name) 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=='='; @@ -2324,6 +2390,7 @@ struct pipe *new_pipe(void) { pi->progs = NULL; pi->next = NULL; pi->followup = 0; /* invalid */ + pi->r_mode = RES_NONE; return pi; } @@ -2349,34 +2416,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); @@ -2453,7 +2521,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++; @@ -2513,9 +2581,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 @@ -2730,15 +2798,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) { @@ -2780,7 +2868,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__ @@ -2866,8 +2962,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 { @@ -3036,8 +3135,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. @@ -3046,11 +3145,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 */ } @@ -3070,7 +3169,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__ @@ -3088,7 +3187,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 { @@ -3161,14 +3271,28 @@ int parse_file_outer(void) } #ifdef __U_BOOT__ +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; + } +} + 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; + u_boot_hush_reloc(); + } return 0; } @@ -3199,7 +3323,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. */ @@ -3248,7 +3372,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; @@ -3317,7 +3441,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(); } @@ -3332,7 +3459,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);