diff --git a/commands/Kconfig b/commands/Kconfig index e934f29d5..251d8b627 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -509,6 +509,11 @@ endif endmenu +config CMD_BAREBOX_UPDATE + tristate + select BAREBOX_UPDATE + prompt "barebox-update" + config CMD_TIMEOUT tristate prompt "timeout" diff --git a/commands/Makefile b/commands/Makefile index 610be55c6..760664342 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_CMD_READLINK) += readlink.o obj-$(CONFIG_CMD_LN) += ln.o obj-$(CONFIG_CMD_CLK) += clk.o obj-$(CONFIG_CMD_TFTP) += tftp.o +obj-$(CONFIG_CMD_BAREBOX_UPDATE)+= barebox-update.o diff --git a/commands/barebox-update.c b/commands/barebox-update.c new file mode 100644 index 000000000..f550572c9 --- /dev/null +++ b/commands/barebox-update.c @@ -0,0 +1,86 @@ +/* + * barebox-update.c - update barebox + * + * Copyright (c) 2012 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +static int do_barebox_update(int argc, char *argv[]) +{ + int opt, ret; + struct bbu_data data = {}; + + while ((opt = getopt(argc, argv, "t:yf:ld:")) > 0) { + switch (opt) { + case 'd': + data.devicefile = optarg; + break; + case 'f': + data.force = simple_strtoul(optarg, NULL, 0); + data.flags |= BBU_FLAG_FORCE; + break; + case 't': + data.handler_name = optarg; + break; + case 'y': + data.flags |= BBU_FLAG_YES; + break; + case 'l': + printf("registered update handlers:\n"); + bbu_handlers_list(); + return 0; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (!(argc - optind)) + return COMMAND_ERROR_USAGE; + + data.imagefile = argv[optind]; + + data.image = read_file(data.imagefile, &data.len); + if (!data.image) + return -errno; + + ret = barebox_update(&data); + + free(data.image); + + return ret; +} + +BAREBOX_CMD_HELP_START(barebox_update) +BAREBOX_CMD_HELP_USAGE("barebox_update [OPTIONS] \n") +BAREBOX_CMD_HELP_SHORT("Update barebox to persistent media\n") +BAREBOX_CMD_HELP_OPT("-t ", "\n") +BAREBOX_CMD_HELP_OPT("-d ", "write image to instead of handler default\n") +BAREBOX_CMD_HELP_OPT(" ", "Can be used for debugging purposes (-d /tmpfile)\n") +BAREBOX_CMD_HELP_OPT("-y\t", "yes. Do not ask for confirmation\n") +BAREBOX_CMD_HELP_OPT("-f ", "Set force level\n") +BAREBOX_CMD_HELP_OPT("-l\t", "list registered targets\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(barebox_update) + .cmd = do_barebox_update, + .usage = "update barebox", + BAREBOX_CMD_HELP(cmd_barebox_update_help) +BAREBOX_CMD_END diff --git a/common/Kconfig b/common/Kconfig index 9210739ee..34af2d09f 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -58,6 +58,9 @@ config GLOBALVAR config STDDEV bool +config BAREBOX_UPDATE + bool + menu "General Settings " config LOCALVERSION diff --git a/common/Makefile b/common/Makefile index 132bd0606..d82fc998b 100644 --- a/common/Makefile +++ b/common/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MENU) += menu.o obj-$(CONFIG_PASSWORD) += password.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_FLEXIBLE_BOOTARGS) += bootargs.o +obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o extra-$(CONFIG_MODULES) += module.lds extra-y += barebox_default_env barebox_default_env.h diff --git a/common/bbu.c b/common/bbu.c new file mode 100644 index 000000000..92f8d2b2f --- /dev/null +++ b/common/bbu.c @@ -0,0 +1,150 @@ +/* + * bbu.c - barebox update functions + * + * Copyright (c) 2012 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include + +static LIST_HEAD(bbu_image_handlers); + +int bbu_force(struct bbu_data *data, const char *fmt, ...) +{ + va_list args; + + printf("UPDATE: "); + + va_start(args, fmt); + + vprintf(fmt, args); + + va_end(args); + + if (!(data->flags & BBU_FLAG_FORCE)) + goto out; + + if (!data->force) + goto out; + + data->force--; + + printf(" (forced)\n"); + + return 1; +out: + printf("\n"); + + return 0; +} + +int bbu_confirm(struct bbu_data *data) +{ + int key; + + if (data->flags & BBU_FLAG_YES) + return 0; + + printf("update barebox from %s using handler %s to %s (y/n)?\n", + data->imagefile, data->handler_name, + data->devicefile); + + key = read_key(); + + if (key == 'y') + return 0; + + return -EINTR; +} + +static struct bbu_handler *bbu_find_handler(const char *name, unsigned long flags) +{ + struct bbu_handler *handler; + + list_for_each_entry(handler, &bbu_image_handlers, list) { + if (!name) { + if (flags & BBU_HANDLER_FLAG_DEFAULT) + return handler; + continue; + } + + if (!strcmp(handler->name, name)) + return handler; + } + + return NULL; +} + +/* + * do a barebox update with data from *data + */ +int barebox_update(struct bbu_data *data) +{ + struct bbu_handler *handler; + int ret; + + handler = bbu_find_handler(data->handler_name, data->flags); + if (!handler) + return -ENODEV; + + if (!data->devicefile) + data->devicefile = handler->devicefile; + + ret = handler->handler(handler, data); + if (ret == -EINTR) + printf("update aborted\n"); + + if (!ret) + printf("update succeeded\n"); + + return ret; +} + +/* + * print a list of all registered update handlers + */ +void bbu_handlers_list(void) +{ + struct bbu_handler *handler; + + if (list_empty(&bbu_image_handlers)) + printf("(none)\n"); + + list_for_each_entry(handler, &bbu_image_handlers, list) + printf("%s%-11s -> %-10s\n", + handler->flags & BBU_HANDLER_FLAG_DEFAULT ? + "* " : " ", + handler->name, + handler->devicefile); +} + +/* + * register a new update handler + */ +int bbu_register_handler(struct bbu_handler *handler) +{ + if (bbu_find_handler(handler->name, 0)) + return -EBUSY; + + if (handler->flags & BBU_HANDLER_FLAG_DEFAULT && + bbu_find_handler(NULL, BBU_HANDLER_FLAG_DEFAULT)) + return -EBUSY; + + list_add_tail(&handler->list, &bbu_image_handlers); + + return 0; +} diff --git a/include/bbu.h b/include/bbu.h new file mode 100644 index 000000000..095eebcf4 --- /dev/null +++ b/include/bbu.h @@ -0,0 +1,49 @@ +#ifndef __INCLUDE_BBU_H +#define __INCLUDE_BBU_H + +struct bbu_data { +#define BBU_FLAG_FORCE (1 << 0) +#define BBU_FLAG_YES (1 << 1) + unsigned long flags; + int force; + void *image; + const char *imagefile; + const char *devicefile; + size_t len; + const char *handler_name; +}; + +struct bbu_handler { + int (*handler)(struct bbu_handler *, struct bbu_data *); + const char *name; + struct list_head list; +#define BBU_HANDLER_FLAG_DEFAULT (1 << 0) + unsigned long flags; + + /* default device file, can be overwritten on the command line */ + const char *devicefile; +}; + +int bbu_force(struct bbu_data *, const char *fmt, ...) + __attribute__ ((format(__printf__, 2, 3))); + +int bbu_confirm(struct bbu_data *); + +int barebox_update(struct bbu_data *); + +void bbu_handlers_list(void); + +#ifdef CONFIG_BAREBOX_UPDATE + +int bbu_register_handler(struct bbu_handler *); + +#else + +static inline int bbu_register_handler(struct bbu_handler *unused) +{ + return -EINVAL; +} + +#endif + +#endif /* __INCLUDE_BBU_H */