X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fhush.c;h=3f3a79c5084209acf6ab0528ca71a73343ec7f70;hb=d104a0c6a19da2d35cfae447e909b5bda727895a;hp=75c18ce8ae0b58d9273916842ecc78caa9f1e5ac;hpb=42246dacf60d5028d3a48a220ce94efcf56faec4;p=karo-tx-uboot.git diff --git a/common/hush.c b/common/hush.c index 75c18ce8ae..3f3a79c508 100644 --- a/common/hush.c +++ b/common/hush.c @@ -17,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 @@ -72,20 +71,9 @@ * maybe change map[] to use 2-bit entries * (eventually) remove all the printf's * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ + #define __U_BOOT__ #ifdef __U_BOOT__ #include /* malloc, free, realloc*/ @@ -93,10 +81,10 @@ #include /* readline */ #include #include /* find_cmd */ -/*cmd_boot.c*/ -extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* 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,7 +103,6 @@ extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); / #include /* #include */ -/* #define DEBUG_SHELL */ #if 1 #include "busybox.h" @@ -129,6 +116,7 @@ extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); / #endif #endif #define SPECIAL_VAR_SYMBOL 03 +#define SUBSTED_VAR_SYMBOL 04 #ifndef __U_BOOT__ #define FLAG_EXIT_FROM_LOOP 1 #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ @@ -290,8 +278,7 @@ struct variables { char **global_argv; unsigned int global_argc; #endif -unsigned int last_return_code; -int nesting_level; +static unsigned int last_return_code; #ifndef __U_BOOT__ extern char **environ; /* This is in , but protected with __USE_GNU */ #endif @@ -360,6 +347,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__ @@ -371,7 +363,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, ...) { } @@ -496,11 +488,7 @@ 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); +static char *insert_var_value_sub(char *inp, int tag_subst); #ifndef __U_BOOT__ /* Table of built-in functions. They can be forked or not, depending on @@ -926,20 +914,6 @@ 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) { @@ -1019,23 +993,20 @@ 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 -# ifdef CONFIG_RESET_TO_RETRY - extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); -# else +# 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) { @@ -1075,7 +1046,7 @@ static void get_user_input(struct in_str *i) else { if (console_buffer[0] != '\n') { if (strlen(the_command) + strlen(console_buffer) - < CFG_CBSIZE) { + < CONFIG_SYS_CBSIZE) { n = strlen(the_command); the_command[n-1] = ' '; strcpy(&the_command[n],console_buffer); @@ -1560,7 +1531,6 @@ static int run_pipe_real(struct pipe *pi) int nextin; int flag = do_repeat ? CMD_FLAG_REPEAT : 0; struct child_prog *child; - cmd_tbl_t *cmdtp; char *p; # if __GNUC__ /* Avoid longjmp clobbering */ @@ -1664,66 +1634,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 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"); - return -1; - } - else - flag |= CMD_FLAG_BOOTD; - } -#endif - /* 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, NULL); +#endif } +#ifndef __U_BOOT__ for (i = 0; i < pi->num_progs; i++) { child = & (pi->progs[i]); @@ -2003,7 +1937,7 @@ static int free_pipe(struct pipe *pi, int indent) #ifndef __U_BOOT__ globfree(&child->glob_result); #else - for (a = child->argc;a >= 0;a--) { + for (a = 0; a < child->argc; a++) { free(child->argv[a]); } free(child->argv); @@ -2178,7 +2112,7 @@ 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; @@ -2200,7 +2134,7 @@ 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; @@ -2226,7 +2160,7 @@ static int set_local_var(const char *s, int flg_export) * NAME=VALUE format. So the first order of business is to * split 's' on the '=' into 'name' and 'value' */ value = strchr(name, '='); - if (value==0 && ++value==0) { + if (value == NULL && ++value == NULL) { free(name); return -1; } @@ -2261,13 +2195,13 @@ static int set_local_var(const char *s, int flg_export) result = -1; } else { cur->name = strdup(name); - if(cur->name == 0) { + if (cur->name == NULL) { free(cur); result = -1; } else { struct variables *bottom = top_vars; cur->value = strdup(value); - cur->next = 0; + cur->next = NULL; cur->flg_export = flg_export; cur->flg_read_only = 0; while(bottom->next) bottom=bottom->next; @@ -2291,8 +2225,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; @@ -2301,14 +2234,16 @@ static void unset_local_var(const char *name) if(strcmp(cur->name, name)==0) break; } - if(cur!=0) { + if (cur != NULL) { struct variables *next = top_vars; if(cur->flg_read_only) { 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) @@ -2319,7 +2254,6 @@ static void unset_local_var(const char *name) } } } -#endif static int is_assignment(const char *s) { @@ -2383,7 +2317,8 @@ static int setup_redirect(struct p_context *ctx, int fd, redir_type style, } #endif -struct pipe *new_pipe(void) { +static struct pipe *new_pipe(void) +{ struct pipe *pi; pi = xmalloc(sizeof(struct pipe)); pi->num_progs = 0; @@ -2441,7 +2376,7 @@ static struct reserved_combo reserved_list[] = { }; #define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo)) -int reserved_word(o_string *dest, struct p_context *ctx) +static int reserved_word(o_string *dest, struct p_context *ctx) { struct reserved_combo *r; for (r=reserved_list; @@ -2799,13 +2734,50 @@ static int parse_group(o_string *dest, struct p_context *ctx, static char *lookup_param(char *src) { char *p; + char *sep; + char *default_val = NULL; + int assign = 0; + int expand_empty = 0; if (!src) return NULL; - p = getenv(src); - if (!p) - p = get_local_var(src); + sep = strchr(src, ':'); + + if (sep) { + *sep = '\0'; + if (*(sep + 1) == '-') + default_val = sep+2; + if (*(sep + 1) == '=') { + default_val = sep+2; + assign = 1; + } + if (*(sep + 1) == '+') { + default_val = sep+2; + expand_empty = 1; + } + } + + p = getenv(src); + if (!p) + p = get_local_var(src); + + if (!p || strlen(p) == 0) { + p = default_val; + if (assign) { + char *var = malloc(strlen(src)+strlen(default_val)+2); + if (var) { + sprintf(var, "%s=%s", src, default_val); + set_local_var(var, 0); + } + free(var); + } + } else if (expand_empty) { + p += strlen(p); + } + + if (sep) + *sep = ':'; return p; } @@ -2941,8 +2913,8 @@ int parse_string(o_string *dest, struct p_context *ctx, const char *src) #endif /* return code is 0 for normal exit, 1 for syntax error */ -int parse_stream(o_string *dest, struct p_context *ctx, - struct in_str *input, int end_trigger) +static int parse_stream(o_string *dest, struct p_context *ctx, + struct in_str *input, int end_trigger) { unsigned int ch, m; #ifndef __U_BOOT__ @@ -3107,6 +3079,21 @@ int parse_stream(o_string *dest, struct p_context *ctx, return 1; break; #endif + case SUBSTED_VAR_SYMBOL: + dest->nonnull = 1; + while (ch = b_getch(input), ch != EOF && + ch != SUBSTED_VAR_SYMBOL) { + debug_printf("subst, pass=%d\n", ch); + if (input->__promptme == 0) + return 1; + b_addchr(dest, ch); + } + debug_printf("subst, term=%d\n", ch); + if (ch == EOF) { + syntax(); + return 1; + } + break; default: syntax(); /* this is really an internal logic error */ return 1; @@ -3126,13 +3113,13 @@ int parse_stream(o_string *dest, struct p_context *ctx, return 0; } -void mapset(const unsigned char *set, int code) +static void mapset(const unsigned char *set, int code) { const unsigned char *s; for (s=set; *s; s++) map[*s] = code; } -void update_ifs_map(void) +static void update_ifs_map(void) { /* char *ifs and char map[256] are both globals. */ ifs = (uchar *)getenv("IFS"); @@ -3148,6 +3135,10 @@ void update_ifs_map(void) mapset((uchar *)"\\$'\"`", 3); /* never flow through */ mapset((uchar *)"<>;&|(){}#", 1); /* flow through if quoted */ #else + { + uchar subst[2] = {SUBSTED_VAR_SYMBOL, 0}; + mapset(subst, 3); /* never flow through */ + } mapset((uchar *)"\\$'\"", 3); /* never flow through */ mapset((uchar *)";&|#", 1); /* flow through if quoted */ #endif @@ -3156,7 +3147,7 @@ void update_ifs_map(void) /* most recursion does not come through here, the exeception is * from builtin_source() */ -int parse_stream_outer(struct in_str *inp, int flag) +static int parse_stream_outer(struct in_str *inp, int flag) { struct p_context ctx; @@ -3227,7 +3218,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; @@ -3271,6 +3262,7 @@ int parse_file_outer(void) } #ifdef __U_BOOT__ +#ifdef CONFIG_NEEDS_MANUAL_RELOC static void u_boot_hush_reloc(void) { unsigned long addr; @@ -3281,6 +3273,7 @@ static void u_boot_hush_reloc(void) r->literal = (char *)addr; } } +#endif int u_boot_hush_start(void) { @@ -3288,10 +3281,12 @@ 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->next = NULL; top_vars->flg_export = 0; top_vars->flg_read_only = 1; +#ifdef CONFIG_NEEDS_MANUAL_RELOC u_boot_hush_reloc(); +#endif } return 0; } @@ -3348,7 +3343,7 @@ static void setup_job_control(void) tcsetpgrp(shell_terminal, shell_pgrp); } -int hush_main(int argc, char **argv) +int hush_main(int argc, char * const *argv) { int opt; FILE *input; @@ -3482,6 +3477,11 @@ final_return: #endif static char *insert_var_value(char *inp) +{ + return insert_var_value_sub(inp, 0); +} + +static char *insert_var_value_sub(char *inp, int tag_subst) { int res_str_len = 0; int len; @@ -3489,19 +3489,46 @@ static char *insert_var_value(char *inp) char *p, *p1, *res_str = NULL; while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { + /* check the beginning of the string for normal charachters */ if (p != inp) { + /* copy any charachters to the result string */ len = p - inp; res_str = xrealloc(res_str, (res_str_len + len)); strncpy((res_str + res_str_len), inp, len); res_str_len += len; } inp = ++p; + /* find the ending marker */ p = strchr(inp, SPECIAL_VAR_SYMBOL); *p = '\0'; + /* look up the value to substitute */ if ((p1 = lookup_param(inp))) { - len = res_str_len + strlen(p1); + if (tag_subst) + len = res_str_len + strlen(p1) + 2; + else + len = res_str_len + strlen(p1); res_str = xrealloc(res_str, (1 + len)); - strcpy((res_str + res_str_len), p1); + if (tag_subst) { + /* + * copy the variable value to the result + * string + */ + strcpy((res_str + res_str_len + 1), p1); + + /* + * mark the replaced text to be accepted as + * is + */ + res_str[res_str_len] = SUBSTED_VAR_SYMBOL; + res_str[res_str_len + 1 + strlen(p1)] = + SUBSTED_VAR_SYMBOL; + } else + /* + * copy the variable value to the result + * string + */ + strcpy((res_str + res_str_len), p1); + res_str_len = len; } *p = SPECIAL_VAR_SYMBOL; @@ -3565,9 +3592,14 @@ static char * make_string(char ** inp) char *str = NULL; int n; int len = 2; + char *noeval_str; + int noeval = 0; + noeval_str = get_local_var("HUSH_NO_EVAL"); + if (noeval_str != NULL && *noeval_str != '0' && *noeval_str != '\0') + noeval = 1; for (n = 0; inp[n]; n++) { - p = insert_var_value(inp[n]); + p = insert_var_value_sub(inp[n], noeval); str = xrealloc(str, (len + strlen(p))); if (n) { strcat(str, " "); @@ -3584,5 +3616,53 @@ static char * make_string(char ** inp) return str; } -#endif /* CFG_HUSH_PARSER */ +#ifdef __U_BOOT__ +static 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 /****************************************************************************/