X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fhush.c;h=3f3a79c5084209acf6ab0528ca71a73343ec7f70;hb=878a095e441284e64e84edc77ad93c616f9ec174;hp=cf5782a7cdb8f4d80d8e95606bc7e431107d72c5;hpb=e915f8bb73d74178bc21d3a457959883b1afd1c0;p=karo-tx-uboot.git diff --git a/common/hush.c b/common/hush.c index cf5782a7cd..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,8 +81,9 @@ #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 #ifndef __U_BOOT__ #include /* isalpha, isdigit */ @@ -127,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 */ @@ -288,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 @@ -499,7 +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); +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 @@ -925,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) { @@ -1018,14 +993,11 @@ static void get_user_input(struct in_str *i) fflush(stdout); i->p = the_command; #else - extern char console_buffer[CONFIG_SYS_CBSIZE]; int n; 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(); @@ -1559,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 */ @@ -1663,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) { - cmd_usage(cmdtp); - 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]); @@ -2002,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); @@ -2177,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; @@ -2225,7 +2160,7 @@ 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; } @@ -2260,13 +2195,13 @@ 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; @@ -2299,7 +2234,7 @@ 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); @@ -2382,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; @@ -2440,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; @@ -2798,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; } @@ -2940,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__ @@ -3106,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; @@ -3125,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"); @@ -3147,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 @@ -3155,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; @@ -3226,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; @@ -3270,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; @@ -3280,6 +3273,7 @@ static void u_boot_hush_reloc(void) r->literal = (char *)addr; } } +#endif int u_boot_hush_start(void) { @@ -3287,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; } @@ -3347,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; @@ -3481,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; @@ -3488,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; @@ -3564,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,7 +3617,8 @@ static char * make_string(char ** inp) } #ifdef __U_BOOT__ -int do_showvar (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_showvar(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { int i, k; int rcode = 0; @@ -3627,7 +3661,7 @@ U_BOOT_CMD( "print local hushshell variables", "\n - print values of all hushshell variables\n" "showvar name ...\n" - " - print value of hushshell variable 'name'\n" + " - print value of hushshell variable 'name'" ); #endif