summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/Kconfig5
-rw-r--r--common/Makefile1
-rw-r--r--common/binfmt.c95
-rw-r--r--common/hush.c31
-rw-r--r--include/binfmt.h39
5 files changed, 159 insertions, 12 deletions
diff --git a/common/Kconfig b/common/Kconfig
index a997f3dc20..73d620a576 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -43,6 +43,10 @@ config HAVE_NOSHELL
config FILETYPE
bool
+config BINFMT
+ bool
+ select FILETYPE
+
menu "General Settings "
config LOCALVERSION
@@ -275,6 +279,7 @@ choice
select ENVIRONMENT_VARIABLES
select COMMAND_SUPPORT
select PARAMETER
+ select BINFMT
help
Enable hush support. This is the most advanced shell available
for barebox.
diff --git a/common/Makefile b/common/Makefile
index bfde73cd44..a58aef94c8 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_BINFMT) += binfmt.o
obj-$(CONFIG_SHELL_HUSH) += hush.o
obj-$(CONFIG_SHELL_SIMPLE) += parser.o
obj-$(CONFIG_GREGORIAN_CALENDER) += date.o
diff --git a/common/binfmt.c b/common/binfmt.c
new file mode 100644
index 0000000000..7dcf5d737d
--- /dev/null
+++ b/common/binfmt.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2
+ */
+
+#include <common.h>
+#include <binfmt.h>
+#include <libbb.h>
+#include <malloc.h>
+#include <command.h>
+#include <errno.h>
+
+static LIST_HEAD(binfmt_hooks);
+
+static int binfmt_run(char *file, int argc, char **argv)
+{
+ struct binfmt_hook *b;
+ enum filetype type = file_name_detect_type(file);
+ int ret;
+
+ list_for_each_entry(b, &binfmt_hooks, list) {
+ if (b->type != type)
+ continue;
+
+ ret = b->hook(b, file, argc, argv);
+ if (ret != -ERESTARTNOHAND)
+ return ret;
+ }
+ return -ENOENT;
+}
+
+/*
+ * This converts the original '/executable <args>' into
+ * 'barebox_cmd <args> /executable'
+ */
+static int binfmt_exec_excute(struct binfmt_hook *b, char *file, int argc, char **argv)
+{
+ char **newargv = xzalloc(sizeof(char*) * (argc + 1));
+ int ret, i;
+
+ newargv[0] = b->exec;
+
+ for (i = 1 ; i < argc; i++)
+ newargv[i] = argv[i];
+ newargv[i] = file;
+
+ ret = execute_binfmt(argc + 1, newargv);
+
+ free(newargv);
+
+ return ret;
+}
+
+int execute_binfmt(int argc, char **argv)
+{
+ int ret;
+ char *path;
+
+ if (strchr(argv[0], '/'))
+ return binfmt_run(argv[0], argc, argv);
+
+ path = find_execable(argv[0]);
+ if (path) {
+ ret = binfmt_run(path, argc, argv);
+ free(path);
+ return ret;
+ }
+
+ return execute_command(argc, &argv[0]);
+}
+
+int binfmt_register(struct binfmt_hook *b)
+{
+ if (!b || !b->type)
+ return -EIO;
+
+ if (!b->hook && !b->exec)
+ return -EIO;
+
+ if (b->exec)
+ b->hook = binfmt_exec_excute;
+
+ list_add_tail(&b->list, &binfmt_hooks);
+
+ return 0;
+}
+
+void binfmt_unregister(struct binfmt_hook *b)
+{
+ if (!b)
+ return;
+
+ list_del(&b->list);
+}
diff --git a/common/hush.c b/common/hush.c
index 053d9a583e..2d89f2b3f2 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -124,6 +124,8 @@
#include <libbb.h>
#include <magicvar.h>
#include <linux/list.h>
+#include <binfmt.h>
+#include <init.h>
/*cmd_boot.c*/
extern int do_bootd(int flag, int argc, char *argv[]); /* do_bootd */
@@ -572,8 +574,6 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
int nextin;
struct child_prog *child;
char *p;
- char *path;
- int ret;
# if __GNUC__
/* Avoid longjmp clobbering */
(void) &i;
@@ -642,16 +642,7 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
if (!strcmp(child->argv[i], "getopt"))
return builtin_getopt(ctx, child);
#endif
- if (strchr(child->argv[i], '/')) {
- return execute_script(child->argv[i], child->argc-i, &child->argv[i]);
- }
- if ((path = find_execable(child->argv[i]))) {
- ret = execute_script(path, child->argc-i, &child->argv[i]);
- free(path);
- return ret;
- }
-
- return execute_command(child->argc - i, &child->argv[i]);
+ return execute_binfmt(child->argc - i, &child->argv[i]);
}
return -1;
}
@@ -1749,6 +1740,22 @@ BAREBOX_MAGICVAR(PATH, "colon seperated list of pathes to search for executables
BAREBOX_MAGICVAR(PS1, "hush prompt");
#endif
+static int binfmt_sh_excute(struct binfmt_hook *b, char *file, int argc, char **argv)
+{
+ return execute_script(file, argc, argv);
+}
+
+static struct binfmt_hook binfmt_sh_hook = {
+ .type = filetype_sh,
+ .hook = binfmt_sh_excute,
+};
+
+static int binfmt_sh_init(void)
+{
+ return binfmt_register(&binfmt_sh_hook);
+}
+fs_initcall(binfmt_sh_init);
+
/**
* @file
* @brief A prototype Bourne shell grammar parser
diff --git a/include/binfmt.h b/include/binfmt.h
new file mode 100644
index 0000000000..46b627e36d
--- /dev/null
+++ b/include/binfmt.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2
+ */
+
+#ifndef __BFMT_H__
+#define __BFMT_H__
+
+#include <filetype.h>
+#include <linux/list.h>
+
+struct binfmt_hook {
+ enum filetype type;
+ int (*hook)(struct binfmt_hook *b, char *file, int argc, char **argv);
+ char *exec;
+
+ struct list_head list;
+};
+
+#ifdef CONFIG_BINFMT
+int binfmt_register(struct binfmt_hook *b);
+void binfmt_unregister(struct binfmt_hook *b);
+
+int execute_binfmt(int argc, char **argv);
+#else
+static inline int binfmt_register(struct binfmt_hook *b)
+{
+ return -EINVAL;
+}
+static inline void binfmt_unregister(struct binfmt_hook *b) {}
+
+static inline int execute_binfmt(int argc, char **argv)
+{
+ return 1;
+}
+#endif
+
+#endif /* __BFMT_H__ */