diff options
-rw-r--r-- | shell/hush.c | 141 |
1 files changed, 98 insertions, 43 deletions
diff --git a/shell/hush.c b/shell/hush.c index 16a4d73e7..9c2c0f324 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2322,6 +2322,9 @@ static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4]; char *heredoc_argv[4]; struct variable *cur; +#if ENABLE_HUSH_FUNCTIONS + struct function *funcp; +#endif char **argv, **pp; unsigned cnt; @@ -2341,7 +2344,7 @@ static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) , (unsigned) G.last_exitcode USE_HUSH_LOOPS(, G.depth_of_loop) ); - /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> + /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> <funcs...> * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL */ cnt = 6; @@ -2349,6 +2352,10 @@ static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) if (!cur->flg_export || cur->flg_read_only) cnt += 2; } +#if ENABLE_HUSH_FUNCTIONS + for (funcp = G.top_func; funcp; funcp = funcp->next) + cnt += 3; +#endif pp = g_argv; while (*pp++) cnt++; @@ -2366,7 +2373,13 @@ static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) *pp++ = cur->varstr; } } -//TODO: pass functions +#if ENABLE_HUSH_FUNCTIONS + for (funcp = G.top_func; funcp; funcp = funcp->next) { + *pp++ = (char *) "-F"; + *pp++ = funcp->name; + *pp++ = funcp->body_as_string; + } +#endif /* We can pass activated traps here. Say, -Tnn:trap_string * * However, POSIX says that subshells reset signals with traps @@ -2649,6 +2662,15 @@ static void free_pipe_list(struct pipe *head) static int run_list(struct pipe *pi); +#if BB_MMU +#define parse_stream(pstring, input, end_trigger) \ + parse_stream(input, end_trigger) +#endif +static struct pipe *parse_stream(char **pstring, + struct in_str *input, + int end_trigger); +static void parse_and_run_string(const char *s); + static const struct built_in_command* find_builtin(const char *name) { @@ -2676,6 +2698,52 @@ static const struct function *find_function(const char *name) return funcp; } +/* Note: takes ownership on name ptr */ +static struct function *new_function(char *name) +{ + struct function *funcp; + struct function **funcpp = &G.top_func; + + while ((funcp = *funcpp) != NULL) { + struct command *cmd; + + if (strcmp(funcp->name, name) != 0) { + funcpp = &funcp->next; + continue; + } + + cmd = funcp->parent_cmd; + debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd); + if (!cmd) { + debug_printf_exec("freeing & replacing function '%s'\n", funcp->name); + free(funcp->name); + /* Note: if !funcp->body, do not free body_as_string! + * This is a special case of "-F name body" function: + * body_as_string was not malloced! */ + if (funcp->body) { + free_pipe_list(funcp->body); +#if !BB_MMU + free(funcp->body_as_string); +#endif + } + } else { + debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name); + cmd->argv[0] = funcp->name; + cmd->group = funcp->body; +#if !BB_MMU + cmd->group_as_string = funcp->body_as_string; +#endif + } + goto skip; + } + debug_printf_exec("remembering new function '%s'\n", command->argv[0]); + funcp = *funcpp = xzalloc(sizeof(*funcp)); + /*funcp->next = NULL;*/ + skip: + funcp->name = name; + return funcp; +} + static void exec_function(const struct function *funcp, char **argv) NORETURN; static void exec_function(const struct function *funcp, char **argv) { @@ -2687,6 +2755,7 @@ static void exec_function(const struct function *funcp, char **argv) while (*++argv) n++; G.global_argc = n; + /* On MMU, funcp->body is always non-NULL */ n = run_list(funcp->body); fflush(NULL); _exit(n); @@ -2719,7 +2788,17 @@ static int run_function(const struct function *funcp, char **argv) G.global_argc = n; G.global_argv = argv; - n = run_list(funcp->body); + /* On MMU, funcp->body is always non-NULL */ +#if !BB_MMU + if (!funcp->body) { + /* Function defined by -F */ + parse_and_run_string(funcp->body_as_string); + n = G.last_exitcode; + } else +#endif + { + n = run_list(funcp->body); + } if (G.global_args_malloced) { /* function ran "set -- arg1 arg2 ..." */ @@ -3201,37 +3280,9 @@ static int run_pipe(struct pipe *pi) if (command->grp_type == GRP_FUNCTION) { /* "executing" func () { list } */ struct function *funcp; - struct function **funcpp = &G.top_func; - - while ((funcp = *funcpp) != NULL) { - if (strcmp(funcp->name, command->argv[0]) == 0) { - struct command *cmd = funcp->parent_cmd; - debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd); - if (!cmd) { - debug_printf_exec("freeing & replacing function '%s'\n", funcp->name); - free(funcp->name); - free_pipe_list(funcp->body); -#if !BB_MMU - free(funcp->body_as_string); -#endif - } else { - debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name); - cmd->argv[0] = funcp->name; - cmd->group = funcp->body; -#if !BB_MMU - cmd->group_as_string = funcp->body_as_string; -#endif - } - goto skip; - } - funcpp = &funcp->next; - } - debug_printf_exec("remembering new function '%s'\n", command->argv[0]); - funcp = *funcpp = xzalloc(sizeof(*funcp)); - /*funcp->next = NULL;*/ - skip: - funcp->name = command->argv[0]; + funcp = new_function(command->argv[0]); + /* funcp->name is already set to argv[0] */ funcp->body = command->group; #if !BB_MMU funcp->body_as_string = command->group_as_string; @@ -4599,15 +4650,6 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_ } -#if BB_MMU -#define parse_stream(pstring, input, end_trigger) \ - parse_stream(input, end_trigger) -#endif -static struct pipe *parse_stream(char **pstring, - struct in_str *input, - int end_trigger); -static void parse_and_run_string(const char *s); - #if ENABLE_HUSH_TICK static FILE *generate_stream_from_string(const char *s) { @@ -5866,7 +5908,10 @@ int hush_main(int argc, char **argv) while (1) { opt = getopt(argc, argv, "c:xins" #if !BB_MMU - "<:$:!:?:D:R:V:" + "<:$:R:V:" +# if ENABLE_HUSH_FUNCTIONS + "F:" +# endif #endif ); if (opt <= 0) @@ -5913,6 +5958,16 @@ int hush_main(int argc, char **argv) case 'V': set_local_var(xstrdup(optarg), 0, opt == 'R'); break; +# if ENABLE_HUSH_FUNCTIONS + case 'F': { + struct function *funcp = new_function(optarg); + /* funcp->name is already set to optarg */ + /* funcp->body is set to NULL. It's a special case. */ + funcp->body_as_string = argv[optind]; + optind++; + break; + } +# endif #endif case 'n': case 'x': |