summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c141
1 files changed, 98 insertions, 43 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 16a4d73..9c2c0f3 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':