diff --git a/common/Kconfig b/common/Kconfig index a997f3dc2..73d620a57 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 bfde73cd4..a58aef94c 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 000000000..7dcf5d737 --- /dev/null +++ b/common/binfmt.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * GPL v2 + */ + +#include +#include +#include +#include +#include +#include + +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 ' into + * 'barebox_cmd /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 053d9a583..2d89f2b3f 100644 --- a/common/hush.c +++ b/common/hush.c @@ -124,6 +124,8 @@ #include #include #include +#include +#include /*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 000000000..46b627e36 --- /dev/null +++ b/include/binfmt.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * GPL v2 + */ + +#ifndef __BFMT_H__ +#define __BFMT_H__ + +#include +#include + +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__ */