]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/hush.c
Merge branch 'master' of git://git.denx.de/u-boot-i2c
[karo-tx-uboot.git] / common / hush.c
index 9aef6e41dbfdbec4a6b3be491db09cd3744c6068..3f3a79c5084209acf6ab0528ca71a73343ec7f70 100644 (file)
@@ -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
  *      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.h>         /* malloc, free, realloc*/
 #include <common.h>        /* readline */
 #include <hush.h>
 #include <command.h>        /* 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 CONFIG_SYS_HUSH_PARSER
 #ifndef __U_BOOT__
 #include <ctype.h>     /* isalpha, isdigit */
 #include <unistd.h>    /* getpid */
@@ -128,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 */
@@ -289,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 <unistd.h>, but protected with __USE_GNU */
 #endif
@@ -500,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
@@ -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,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();
@@ -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;
 
@@ -2226,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;
        }
@@ -2261,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;
@@ -2300,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);
@@ -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, " ");
@@ -3585,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;
@@ -3625,12 +3658,11 @@ int do_showvar (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 
 U_BOOT_CMD(
        showvar, CONFIG_SYS_MAXARGS, 1, do_showvar,
-       "showvar- print local hushshell variables\n",
+       "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
-#endif /* CONFIG_SYS_HUSH_PARSER */
 /****************************************************************************/