barebox/common/binfmt.c
Sascha Hauer 45212cdd72 command: Let builtin command take precedence
In theory we can overwrite a builtin command with a script. However,
I don't know a single case where this has been done. Scripts are
often more unflexible than commands so it's unlikely that a script
can extend the functionality of a builtin command. Moreover, the
internal command is no longer accessible once it's overwritten by
a script.

Invert this logic so that a builtin command can overwrite an existing
script. This will help when the 'boot' script is converted to a
builting command. Then with old environments the builtin command will
be used instead of the script.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
2013-09-24 09:03:18 +02:00

99 lines
1.6 KiB
C

/*
* 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);
if (find_cmd(argv[0]))
return execute_command(argc, &argv[0]);
path = find_execable(argv[0]);
if (path) {
ret = binfmt_run(path, argc, argv);
free(path);
return ret;
}
return -ENOENT;
}
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);
}