diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2021-05-17 16:23:51 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-05-17 16:23:51 +0200 |
commit | dee7a15dfaa640130d0b9bc289e5d55b358a2dbc (patch) | |
tree | 8ea7b1c341b1ea5453d1a3576fb238dc21edaa37 | |
parent | c5e0e697de769d0e78a00b1cb47fe864fade9974 (diff) | |
parent | 7ef2912d40b52202f563806fbffb9f615d2d2220 (diff) | |
download | barebox-dee7a15dfaa640130d0b9bc289e5d55b358a2dbc.tar.gz barebox-dee7a15dfaa640130d0b9bc289e5d55b358a2dbc.tar.xz |
Merge branch 'for-next/usb-gadget'
-rw-r--r-- | common/Kconfig | 15 | ||||
-rw-r--r-- | common/Makefile | 3 | ||||
-rw-r--r-- | common/bbu.c | 24 | ||||
-rw-r--r-- | common/console_common.c | 20 | ||||
-rw-r--r-- | common/fastboot.c | 28 | ||||
-rw-r--r-- | common/file-list.c | 85 | ||||
-rw-r--r-- | common/system-partitions.c | 44 | ||||
-rw-r--r-- | common/usbgadget.c | 94 | ||||
-rw-r--r-- | drivers/usb/gadget/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/dfu.c | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/multi.c | 18 | ||||
-rw-r--r-- | fs/fs.c | 6 | ||||
-rw-r--r-- | include/bbu.h | 10 | ||||
-rw-r--r-- | include/fastboot.h | 6 | ||||
-rw-r--r-- | include/file-list.h | 12 | ||||
-rw-r--r-- | include/linux/string.h | 10 | ||||
-rw-r--r-- | include/param.h | 15 | ||||
-rw-r--r-- | include/printk.h | 1 | ||||
-rw-r--r-- | include/progress.h | 43 | ||||
-rw-r--r-- | include/string.h | 1 | ||||
-rw-r--r-- | include/stringlist.h | 1 | ||||
-rw-r--r-- | include/system-partitions.h | 40 | ||||
-rw-r--r-- | include/usb/gadget-multi.h | 1 | ||||
-rw-r--r-- | lib/Kconfig | 6 | ||||
-rw-r--r-- | lib/parameter.c | 88 | ||||
-rw-r--r-- | lib/show_progress.c | 28 | ||||
-rw-r--r-- | lib/string.c | 9 | ||||
-rw-r--r-- | lib/stringlist.c | 30 | ||||
-rw-r--r-- | lib/vsprintf.c | 13 | ||||
-rw-r--r-- | net/Kconfig | 1 | ||||
-rw-r--r-- | net/fastboot.c | 4 |
31 files changed, 573 insertions, 88 deletions
diff --git a/common/Kconfig b/common/Kconfig index 758acb751d..db7cc6713a 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -91,9 +91,6 @@ config EFI_GUID config EFI_DEVICEPATH bool -config FILE_LIST - bool - config ARCH_DMA_ADDR_T_64BIT bool @@ -117,7 +114,6 @@ config USBGADGET_START bool depends on CMD_USBGADGET || USB_GADGET_AUTOSTART select ENVIRONMENT_VARIABLES - select FILE_LIST default y config BOOT @@ -728,6 +724,17 @@ config MMCBLKDEV_ROOTARG config BAREBOX_UPDATE bool "In-system barebox update infrastructure" +config SYSTEM_PARTITIONS + bool "Generic system partitions support" + depends on GLOBALVAR + help + System partitions are a generic way for boards to specify the + partitions that should be exported for flashing. + Board drivers that set this directly will select this option + automatically. + Say y here if this should be configurable over the + global.system.partitions device parameter as well. + config IMD select CRC32 bool "barebox metadata support" diff --git a/common/Makefile b/common/Makefile index 2c679090a0..382a4f661f 100644 --- a/common/Makefile +++ b/common/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_MACHINE_ID) += machine_id.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o obj-y += version.o obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o +obj-$(CONFIG_SYSTEM_PARTITIONS) += system-partitions.o obj-$(CONFIG_BINFMT) += binfmt.o obj-$(CONFIG_BLOCK) += block.o obj-$(CONFIG_BLSPEC) += blspec.o @@ -65,7 +66,7 @@ obj-$(CONFIG_EFI_GUID) += efi-guid.o obj-$(CONFIG_EFI_DEVICEPATH) += efi-devicepath.o lwl-$(CONFIG_IMD) += imd-barebox.o obj-$(CONFIG_IMD) += imd.o -obj-$(CONFIG_FILE_LIST) += file-list.o +obj-y += file-list.o obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_UBIFORMAT) += ubiformat.o obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o diff --git a/common/bbu.c b/common/bbu.c index ee9f78ecc9..1a1edda96b 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -16,22 +16,28 @@ #include <malloc.h> #include <linux/stat.h> #include <image-metadata.h> +#include <file-list.h> static LIST_HEAD(bbu_image_handlers); -int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *ctx) +static void append_bbu_entry(struct bbu_handler *handler, struct file_list *files) { - struct bbu_handler *handler; + char *name; - list_for_each_entry(handler, &bbu_image_handlers, list) { - int ret; + name = basprintf("bbu-%s", handler->name); - ret = fn(handler, ctx); - if (ret) - return ret; - } + if (file_list_add_entry(files, name, handler->devicefile, 0)) + pr_warn("duplicate partition name %s\n", name); - return 0; + free(name); +} + +void bbu_append_handlers_to_file_list(struct file_list *files) +{ + struct bbu_handler *handler; + + list_for_each_entry(handler, &bbu_image_handlers, list) + append_bbu_entry(handler, files); } int bbu_force(struct bbu_data *data, const char *fmt, ...) diff --git a/common/console_common.c b/common/console_common.c index 98ff8d0ef9..91a81e50fa 100644 --- a/common/console_common.c +++ b/common/console_common.c @@ -183,6 +183,26 @@ static int console_common_init(void) } device_initcall(console_common_init); +int log_writefile(const char *filepath) +{ + int ret = 0, nbytes = 0, fd = -1; + struct log_entry *log; + + fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) + return -errno; + + list_for_each_entry(log, &barebox_logbuf, list) { + ret = dputs(fd, log->msg); + if (ret < 0) + break; + nbytes += ret; + } + + close(fd); + return ret < 0 ? ret : nbytes; +} + void log_print(unsigned flags, unsigned levels) { struct log_entry *log; diff --git a/common/fastboot.c b/common/fastboot.c index a394d07e28..75f6691b08 100644 --- a/common/fastboot.c +++ b/common/fastboot.c @@ -41,6 +41,7 @@ #include <linux/stat.h> #include <linux/mtd/mtd.h> #include <fastboot.h> +#include <system-partitions.h> #define FASTBOOT_VERSION "0.4" @@ -149,21 +150,6 @@ out: return ret; } -static int fastboot_add_bbu_variables(struct bbu_handler *handler, void *ctx) -{ - struct fastboot *fb = ctx; - char *name; - int ret; - - name = basprintf("bbu-%s", handler->name); - - ret = file_list_add_entry(fb->files, name, handler->devicefile, 0); - - free(name); - - return ret; -} - int fastboot_generic_init(struct fastboot *fb, bool export_bbu) { int ret; @@ -185,8 +171,8 @@ int fastboot_generic_init(struct fastboot *fb, bool export_bbu) if (!fb->tempname) return -ENOMEM; - if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && export_bbu) - bbu_handlers_iterate(fastboot_add_bbu_variables, fb); + if (export_bbu) + bbu_append_handlers_to_file_list(fb->files); file_list_for_each_entry(fb->files, fentry) { ret = fastboot_add_partition_variables(fb, fentry); @@ -930,9 +916,13 @@ bool get_fastboot_bbu(void) return fastboot_bbu; } -const char *get_fastboot_partitions(void) +struct file_list *get_fastboot_partitions(void) { - return fastboot_partitions; + if (fastboot_partitions && *fastboot_partitions) + return file_list_parse(fastboot_partitions); + if (!system_partitions_empty()) + return system_partitions_get(); + return NULL; } static int fastboot_globalvars_init(void) diff --git a/common/file-list.c b/common/file-list.c index cd52b5e045..05f44514fb 100644 --- a/common/file-list.c +++ b/common/file-list.c @@ -6,7 +6,9 @@ #include <malloc.h> #include <fs.h> #include <file-list.h> +#include <stringlist.h> #include <linux/err.h> +#include <driver.h> #define PARSE_DEVICE 0 #define PARSE_NAME 1 @@ -109,6 +111,25 @@ static int file_list_parse_one(struct file_list *files, const char *partstr, con return file_list_add_entry(files, name, filename, flags); } +static const char *flags_to_str(int flags) +{ + static char str[sizeof "srcu"]; + char *s = str;; + + if (flags & FILE_LIST_FLAG_SAFE) + *s++ = 's'; + if (flags & FILE_LIST_FLAG_READBACK) + *s++ = 'r'; + if (flags & FILE_LIST_FLAG_CREATE) + *s++ = 'c'; + if (flags & FILE_LIST_FLAG_UBI) + *s++ = 'u'; + + *s = '\0'; + + return str; +} + struct file_list *file_list_parse(const char *str) { struct file_list *files; @@ -141,6 +162,9 @@ void file_list_free(struct file_list *files) { struct file_list_entry *entry, *tmp; + if (!files) + return; + list_for_each_entry_safe(entry, tmp, &files->list, list) { free(entry->name); free(entry->filename); @@ -149,3 +173,64 @@ void file_list_free(struct file_list *files) free(files); } + +struct file_list *file_list_dup(struct file_list *old) +{ + struct file_list_entry *old_entry; + struct file_list *new; + + new = xzalloc(sizeof(*new)); + + INIT_LIST_HEAD(&new->list); + + list_for_each_entry(old_entry, &old->list, list) { + (void)file_list_add_entry(new, old_entry->name, old_entry->filename, + old_entry->flags); /* can't fail */ + new->num_entries++; + } + + return new; +} + +char *file_list_to_str(const struct file_list *files) +{ + struct file_list_entry *entry; + struct string_list sl; + char *str; + + if (!files) + return strdup(""); + + string_list_init(&sl); + + list_for_each_entry(entry, &files->list, list) { + int ret = string_list_add_asprintf(&sl, "%s(%s)%s", entry->filename, entry->name, + flags_to_str(entry->flags)); + if (ret) { + str = ERR_PTR(ret); + goto out; + } + } + + str = string_list_join(&sl, ","); +out: + string_list_free(&sl); + + return str; +} + +int file_list_detect_all(const struct file_list *files) +{ + struct file_list_entry *fentry; + struct stat s; + int i = 0; + + list_for_each_entry(fentry, &files->list, list) { + if (stat(fentry->filename, &s)) + continue; + if (device_detect_by_name(devpath_to_name(fentry->filename)) == 0) + i++; + } + + return i; +} diff --git a/common/system-partitions.c b/common/system-partitions.c new file mode 100644 index 0000000000..547e08a9f3 --- /dev/null +++ b/common/system-partitions.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Ahmad Fatoum, Pengutronix + */ + +#include <file-list.h> +#include <param.h> +#include <globalvar.h> +#include <init.h> +#include <magicvar.h> +#include <system-partitions.h> + +static struct file_list *system_partitions; + +bool system_partitions_empty(void) +{ + return file_list_empty(system_partitions); +} + +struct file_list *system_partitions_get(void) +{ + return file_list_dup(system_partitions); +} + +void system_partitions_set(struct file_list *files) +{ + file_list_free(system_partitions); + system_partitions = files; +} + +static int system_partitions_var_init(void) +{ + struct param_d *param; + + system_partitions = file_list_parse(""); + param = dev_add_param_file_list(&global_device, "system.partitions", + NULL, NULL, &system_partitions, NULL); + + return PTR_ERR_OR_ZERO(param); +} +postcore_initcall(system_partitions_var_init); + +BAREBOX_MAGICVAR(global.system.partitions, + "board-specific list of updatable partitions"); diff --git a/common/usbgadget.c b/common/usbgadget.c index feec0b6634..d4437b5169 100644 --- a/common/usbgadget.c +++ b/common/usbgadget.c @@ -17,6 +17,7 @@ #include <usb/gadget-multi.h> #include <globalvar.h> #include <magicvar.h> +#include <system-partitions.h> static int autostart; static int acm; @@ -24,14 +25,29 @@ static char *dfu_function; static struct file_list *parse(const char *files) { - struct file_list *list = file_list_parse(files); + struct file_list *list; + + if (!files) + return NULL; + + list = file_list_parse(files); if (IS_ERR(list)) { pr_err("Parsing file list \"%s\" failed: %pe\n", files, list); return NULL; } + return list; } +static inline struct file_list *get_dfu_function(void) +{ + if (dfu_function && *dfu_function) + return file_list_parse(dfu_function); + if (!system_partitions_empty()) + return system_partitions_get(); + return NULL; +} + int usbgadget_register(bool dfu, const char *dfu_opts, bool fastboot, const char *fastboot_opts, bool acm, bool export_bbu) @@ -39,46 +55,44 @@ int usbgadget_register(bool dfu, const char *dfu_opts, int ret; struct device_d *dev; struct f_multi_opts *opts; - const char *fastboot_partitions = get_fastboot_partitions(); - - if (dfu && !dfu_opts && dfu_function && *dfu_function) - dfu_opts = dfu_function; - - if (IS_ENABLED(CONFIG_FASTBOOT_BASE) && fastboot && !fastboot_opts && - fastboot_partitions && *fastboot_partitions) - fastboot_opts = fastboot_partitions; - - if (!dfu_opts && !fastboot_opts && !acm) - return COMMAND_ERROR_USAGE; - - /* - * Creating a gadget with both DFU and Fastboot doesn't work. - * Both client tools seem to assume that the device only has - * a single configuration - */ - if (fastboot_opts && dfu_opts) { - pr_err("Only one of Fastboot and DFU allowed\n"); - return -EINVAL; - } opts = xzalloc(sizeof(*opts)); opts->release = usb_multi_opts_release; - if (fastboot_opts) { + if (dfu) { + opts->dfu_opts.files = parse(dfu_opts); + if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && file_list_empty(opts->dfu_opts.files)) { + file_list_free(opts->dfu_opts.files); + opts->dfu_opts.files = get_dfu_function(); + } + } + + if (fastboot) { opts->fastboot_opts.files = parse(fastboot_opts); + if (IS_ENABLED(CONFIG_FASTBOOT_BASE) && file_list_empty(opts->fastboot_opts.files)) { + file_list_free(opts->fastboot_opts.files); + opts->fastboot_opts.files = get_fastboot_partitions(); + } + opts->fastboot_opts.export_bbu = export_bbu; } - if (dfu_opts) - opts->dfu_opts.files = parse(dfu_opts); + opts->create_acm = acm; - if (!opts->dfu_opts.files && !opts->fastboot_opts.files && !acm) { + if (usb_multi_count_functions(opts) == 0) { pr_warn("No functions to register\n"); - free(opts); - return 0; + ret = COMMAND_ERROR_USAGE; + goto err; } - opts->create_acm = acm; + /* + * Creating a gadget with both DFU and Fastboot may not work. + * fastboot 1:8.1.0+r23-5 can deal with it, but dfu-util 0.9 + * seems to assume that the device only has a single configuration + * That's not our fault though. Emit a warning and continue + */ + if (!file_list_empty(opts->fastboot_opts.files) && !file_list_empty(opts->dfu_opts.files)) + pr_warn("Both DFU and Fastboot enabled. dfu-util may not like this!\n"); dev = get_device_by_name("otg"); if (dev) @@ -86,7 +100,11 @@ int usbgadget_register(bool dfu, const char *dfu_opts, ret = usb_multi_register(opts); if (ret) - usb_multi_opts_release(opts); + goto err; + + return 0; +err: + usb_multi_opts_release(opts); return ret; } @@ -97,7 +115,7 @@ static int usbgadget_autostart_set(struct param_d *param, void *ctx) bool fastboot_bbu = get_fastboot_bbu(); int err; - if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART) || !autostart || started) + if (!autostart || started) return 0; err = usbgadget_register(true, NULL, true, NULL, acm, fastboot_bbu); @@ -109,17 +127,21 @@ static int usbgadget_autostart_set(struct param_d *param, void *ctx) static int usbgadget_globalvars_init(void) { - if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) { - globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set, - &autostart, NULL); - globalvar_add_simple_bool("usbgadget.acm", &acm); - } + globalvar_add_simple_bool("usbgadget.acm", &acm); globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function); return 0; } device_initcall(usbgadget_globalvars_init); +static int usbgadget_autostart_init(void) +{ + if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) + globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set, &autostart, NULL); + return 0; +} +postenvironment_initcall(usbgadget_autostart_init); + BAREBOX_MAGICVAR(global.usbgadget.autostart, "usbgadget: Automatically start usbgadget on boot"); BAREBOX_MAGICVAR(global.usbgadget.acm, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 7e0c570914..4ed6cbbee1 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -45,7 +45,6 @@ comment "USB Gadget drivers" config USB_GADGET_DFU bool - select FILE_LIST prompt "Device Firmware Update Gadget" config USB_GADGET_SERIAL @@ -56,7 +55,6 @@ config USB_GADGET_SERIAL config USB_GADGET_FASTBOOT bool select BANNER - select FILE_LIST select FASTBOOT_BASE prompt "Android Fastboot USB Gadget" endif diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c index 1ac63c4642..fd0ec505dc 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/dfu.c @@ -447,8 +447,7 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) i = 0; file_list_for_each_entry(dfu_files, fentry) { - pr_err("register alt%d(%s) with device %s\n", - i, fentry->name, fentry->filename); + pr_info("register alt%d(%s) with device %s\n", i, fentry->name, fentry->filename); i++; } diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 95f5b90c88..144ac0624b 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -266,12 +266,22 @@ void usb_multi_unregister(void) gadget_multi_opts = NULL; } +unsigned usb_multi_count_functions(struct f_multi_opts *opts) +{ + unsigned count = 0; + + count += !file_list_empty(opts->fastboot_opts.files) || + opts->fastboot_opts.export_bbu; + count += !file_list_empty(opts->dfu_opts.files); + count += opts->create_acm; + + return count; +} + void usb_multi_opts_release(struct f_multi_opts *opts) { - if (opts->fastboot_opts.files) - file_list_free(opts->fastboot_opts.files); - if (opts->dfu_opts.files) - file_list_free(opts->dfu_opts.files); + file_list_free(opts->fastboot_opts.files); + file_list_free(opts->dfu_opts.files); free(opts); } @@ -321,13 +321,13 @@ static ssize_t __write(FILE *f, const void *buf, size_t count) struct fs_driver_d *fsdrv; int ret; - if (!(f->flags & O_ACCMODE)) { + fsdrv = f->fsdev->driver; + + if ((f->flags & O_ACCMODE) == O_RDONLY || !fsdrv->write) { ret = -EBADF; goto out; } - fsdrv = f->fsdev->driver; - if (fsdrv != ramfs_driver) assert_command_context(); diff --git a/include/bbu.h b/include/bbu.h index 3b9d2f4bf1..3128339068 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -48,7 +48,7 @@ struct bbu_handler *bbu_find_handler_by_device(const char *devicepath); void bbu_handlers_list(void); -int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *); +struct file_list; #ifdef CONFIG_BAREBOX_UPDATE @@ -57,6 +57,8 @@ int bbu_register_handler(struct bbu_handler *); int bbu_register_std_file_update(const char *name, unsigned long flags, const char *devicefile, enum filetype imagetype); +void bbu_append_handlers_to_file_list(struct file_list *files); + #else static inline int bbu_register_handler(struct bbu_handler *unused) @@ -69,6 +71,12 @@ static inline int bbu_register_std_file_update(const char *name, unsigned long f { return -ENOSYS; } + +static inline void bbu_append_handlers_to_file_list(struct file_list *files) +{ + /* none could be registered, so nothing to do */ +} + #endif #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) diff --git a/include/fastboot.h b/include/fastboot.h index 2eab2dfe6a..cf8a177bf1 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -58,16 +58,16 @@ enum fastboot_msg_type { #ifdef CONFIG_FASTBOOT_BASE bool get_fastboot_bbu(void); -const char *get_fastboot_partitions(void); +struct file_list *get_fastboot_partitions(void); #else static inline int get_fastboot_bbu(void) { return false; } -static inline const char *get_fastboot_partitions(void) +static inline struct file_list *get_fastboot_partitions(void) { - return NULL; + return file_list_parse(""); } #endif diff --git a/include/file-list.h b/include/file-list.h index 9a9edfa378..7e2a4d9205 100644 --- a/include/file-list.h +++ b/include/file-list.h @@ -2,6 +2,8 @@ #ifndef __FILE_LIST #define __FILE_LIST +#include <linux/list.h> + #define FILE_LIST_FLAG_SAFE (1 << 0) #define FILE_LIST_FLAG_READBACK (1 << 1) #define FILE_LIST_FLAG_CREATE (1 << 2) @@ -20,14 +22,24 @@ struct file_list { }; struct file_list *file_list_parse(const char *str); +char *file_list_to_str(const struct file_list *files); void file_list_free(struct file_list *); int file_list_add_entry(struct file_list *files, const char *name, const char *filename, unsigned long flags); +struct file_list *file_list_dup(struct file_list *old); + +int file_list_detect_all(const struct file_list *files); + struct file_list_entry *file_list_entry_by_name(struct file_list *files, const char *name); #define file_list_for_each_entry(files, entry) \ list_for_each_entry(entry, &files->list, list) +static inline bool file_list_empty(struct file_list *files) +{ + return !files || !files->num_entries; +} + #endif /* __FILE_LIST */ diff --git a/include/linux/string.h b/include/linux/string.h index 58e2a4d2ea..55bc905c0e 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -136,4 +136,14 @@ extern int kstrtobool(const char *s, bool *res); int match_string(const char * const *array, size_t n, const char *string); +/** + * strstarts - does @str start with @prefix? + * @str: string to examine + * @prefix: prefix to look for. + */ +static inline bool strstarts(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} + #endif /* _LINUX_STRING_H_ */ diff --git a/include/param.h b/include/param.h index 6aca1b481d..4835be4d25 100644 --- a/include/param.h +++ b/include/param.h @@ -10,6 +10,7 @@ #define PARAM_GLOBALVAR_UNQUALIFIED (1 << 1) struct device_d; +struct file_list; typedef uint32_t IPaddr_t; enum param_type { @@ -23,6 +24,7 @@ enum param_type { PARAM_TYPE_BITMASK, PARAM_TYPE_IPV4, PARAM_TYPE_MAC, + PARAM_TYPE_FILE_LIST, }; struct param_d { @@ -89,6 +91,11 @@ struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, int (*get)(struct param_d *p, void *priv), u8 *mac, void *priv); +struct param_d *dev_add_param_file_list(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + struct file_list **file_list, void *priv); + struct param_d *dev_add_param_fixed(struct device_d *dev, const char *name, const char *value); void dev_remove_param(struct param_d *p); @@ -185,6 +192,14 @@ static inline struct param_d *dev_add_param_mac(struct device_d *dev, const char return NULL; } +static inline struct param_d *dev_add_param_file_list(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + struct file_list **file_list, void *priv) +{ + return NULL; +} + static inline struct param_d *dev_add_param_fixed(struct device_d *dev, const char *name, const char *value) { diff --git a/include/printk.h b/include/printk.h index 94a25ec9eb..f83ad3bf07 100644 --- a/include/printk.h +++ b/include/printk.h @@ -141,6 +141,7 @@ extern void log_clean(unsigned int limit); #define BAREBOX_LOG_PRINT_ALERT BIT(1) #define BAREBOX_LOG_PRINT_EMERG BIT(0) +int log_writefile(const char *filepath); void log_print(unsigned flags, unsigned levels); struct va_format { diff --git a/include/progress.h b/include/progress.h index 50b15fb12b..7230bd3a9b 100644 --- a/include/progress.h +++ b/include/progress.h @@ -3,6 +3,8 @@ #define __PROGRSS_H #include <linux/types.h> +#include <notifier.h> +#include <errno.h> /* Initialize a progress bar. If max > 0 a one line progress * bar is printed where 'max' corresponds to 100%. If max == 0 @@ -15,4 +17,45 @@ void init_progression_bar(loff_t max); */ void show_progress(loff_t now); +extern struct notifier_head progress_notifier; + +enum progress_stage { + PROGRESS_UNSPECIFIED = 0, + PROGRESS_UPDATING, + PROGRESS_UPDATE_SUCCESS, + PROGRESS_UPDATE_FAIL, +}; + +/* + * Notifier list for code which wants to be called at progress + * This could use by board code to e.g. flash a LED during updates + */ +extern struct notifier_head progress_notifier_list; + +/* generic client that just logs the state */ +extern struct notifier_block progress_log_client; + +static inline int progress_register_client(struct notifier_block *nb) +{ + if (!IS_ENABLED(CONFIG_PROGRESS_NOTIFIER)) + return -ENOSYS; + return notifier_chain_register(&progress_notifier_list, nb); +} + +static inline int progress_unregister_client(struct notifier_block *nb) +{ + if (!IS_ENABLED(CONFIG_PROGRESS_NOTIFIER)) + return -ENOSYS; + return notifier_chain_unregister(&progress_notifier_list, nb); +} + +static inline int progress_notifier_call_chain(enum progress_stage stage, const char *prefix) +{ + if (!IS_ENABLED(CONFIG_PROGRESS_NOTIFIER)) + return -ENOSYS; + + /* clients should not modify the prefix */ + return notifier_call_chain(&progress_notifier_list, stage, (char *)(prefix ?: "")); +} + #endif /* __PROGRSS_H */ diff --git a/include/string.h b/include/string.h index ef0b5e199e..d423bee6fb 100644 --- a/include/string.h +++ b/include/string.h @@ -7,6 +7,7 @@ int strtobool(const char *str, int *val); char *strsep_unescaped(char **, const char *); char *stpcpy(char *dest, const char *src); +bool strends(const char *str, const char *postfix); void *__default_memset(void *, int, __kernel_size_t); void *__nokasan_default_memset(void *, int, __kernel_size_t); diff --git a/include/stringlist.h b/include/stringlist.h index c5d6e70a36..01491082ea 100644 --- a/include/stringlist.h +++ b/include/stringlist.h @@ -14,6 +14,7 @@ int string_list_add_asprintf(struct string_list *sl, const char *fmt, ...); int string_list_add_sorted(struct string_list *sl, const char *str); int string_list_add_sort_uniq(struct string_list *sl, const char *str); int string_list_contains(struct string_list *sl, const char *str); +char *string_list_join(const struct string_list *sl, const char *joinstr); void string_list_print_by_column(struct string_list *sl); static inline void string_list_init(struct string_list *sl) diff --git a/include/system-partitions.h b/include/system-partitions.h new file mode 100644 index 0000000000..86de3612cc --- /dev/null +++ b/include/system-partitions.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef SYSTEM_PARTITIONS_H_ +#define SYSTEM_PARTITIONS_H_ + +#include <file-list.h> + +#ifdef CONFIG_SYSTEM_PARTITIONS + +/* duplicates current system_partitions and returns it */ +struct file_list *system_partitions_get(void); + +/* takes ownership of files and store it internally */ +void system_partitions_set(struct file_list *files); + +/* + * check whether system_partitions_get would return an empty + * file_list without doing an allocation + */ +bool system_partitions_empty(void); + +#else + +static inline struct file_list *system_partitions_get(void) +{ + return file_list_parse(""); +} + +static inline bool system_partitions_empty(void) +{ + return true; +} + +/* + * system_partitions_set() intentionally left unimplemented. + * select CONFIG_SYSTEM_PARTITIONS if you want to set it + */ + +#endif + +#endif diff --git a/include/usb/gadget-multi.h b/include/usb/gadget-multi.h index 9bb6c889f3..f30dae5686 100644 --- a/include/usb/gadget-multi.h +++ b/include/usb/gadget-multi.h @@ -15,6 +15,7 @@ struct f_multi_opts { int usb_multi_register(struct f_multi_opts *opts); void usb_multi_unregister(void); void usb_multi_opts_release(struct f_multi_opts *opts); +unsigned usb_multi_count_functions(struct f_multi_opts *opts); int usbgadget_register(bool dfu, const char *dfu_opts, bool fastboot, const char *fastboot_opts, diff --git a/lib/Kconfig b/lib/Kconfig index e5831ecdb9..922710e106 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -154,6 +154,12 @@ source "lib/logo/Kconfig" source "lib/bootstrap/Kconfig" +config PROGRESS_NOTIFIER + bool + help + This is selected by boards that register a notifier to visualize + progress, like blinking a LED during an update. + config PRINTF_UUID bool diff --git a/lib/parameter.c b/lib/parameter.c index 173420c58a..adc3c7cdea 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -27,6 +27,8 @@ #include <string.h> #include <globalvar.h> #include <linux/err.h> +#include <file-list.h> +#include <stringlist.h> static const char *param_type_string[] = { [PARAM_TYPE_STRING] = "string", @@ -39,6 +41,7 @@ static const char *param_type_string[] = { [PARAM_TYPE_BITMASK] = "bitmask", [PARAM_TYPE_IPV4] = "ipv4", [PARAM_TYPE_MAC] = "MAC", + [PARAM_TYPE_FILE_LIST] = "file-list", }; const char *get_param_type(struct param_d *param) @@ -907,6 +910,91 @@ struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, return &pm->param; } +struct param_file_list { + struct param_d param; + struct file_list **file_list; + char *file_list_str; + int (*set)(struct param_d *p, void *priv); + int (*get)(struct param_d *p, void *priv); +}; + +static inline struct param_file_list *to_param_file_list(struct param_d *p) +{ + return container_of(p, struct param_file_list, param); +} + +static int param_file_list_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct param_file_list *pfl = to_param_file_list(p); + struct file_list *file_list_save = *pfl->file_list; + int ret; + + if (!val) + val = ""; + + *pfl->file_list = file_list_parse(val); + if (IS_ERR(*pfl->file_list)) { + ret = PTR_ERR(*pfl->file_list); + goto out; + } + + if (pfl->set) { + ret = pfl->set(p, p->driver_priv); + if (ret) { + file_list_free(*pfl->file_list); + goto out; + } + } + + return 0; +out: + *pfl->file_list = file_list_save; + + return ret; +} + +static const char *param_file_list_get(struct device_d *dev, struct param_d *p) +{ + struct param_file_list *pfl = to_param_file_list(p); + int ret; + + if (pfl->get) { + ret = pfl->get(p, p->driver_priv); + if (ret) + return NULL; + } + + free(p->value); + p->value = file_list_to_str(*pfl->file_list); + return p->value; +} + +struct param_d *dev_add_param_file_list(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + struct file_list **file_list, void *priv) +{ + struct param_file_list *pfl; + int ret; + + pfl = xzalloc(sizeof(*pfl)); + pfl->file_list = file_list; + pfl->set = set; + pfl->get = get; + pfl->param.driver_priv = priv; + pfl->param.type = PARAM_TYPE_FILE_LIST; + + ret = __dev_add_param(&pfl->param, dev, name, + param_file_list_set, param_file_list_get, 0); + if (ret) { + free(pfl); + return ERR_PTR(ret); + } + + return &pfl->param; +} + + /** * dev_remove_param - remove a parameter from a device and free its * memory diff --git a/lib/show_progress.c b/lib/show_progress.c index 1be06ea780..1b624bcb9a 100644 --- a/lib/show_progress.c +++ b/lib/show_progress.c @@ -57,3 +57,31 @@ void init_progression_bar(loff_t max) else printf("\t"); } + +NOTIFIER_HEAD(progress_notifier_list); + +static int progress_logger(struct notifier_block *r, unsigned long stage, void *_prefix) +{ + const char *prefix = _prefix; + + switch ((enum progress_stage)stage) { + case PROGRESS_UPDATING: + pr_info("%sSoftware update in progress\n", prefix); + break; + case PROGRESS_UPDATE_SUCCESS: + pr_info("%sSoftware update finished successfully\n", prefix); + break; + case PROGRESS_UPDATE_FAIL: + pr_info("%sSoftware update failed\n", prefix); + break; + case PROGRESS_UNSPECIFIED: + /* default state. This should not be reached */ + break; + } + + return 0; +} + +struct notifier_block progress_log_client = { + .notifier_call = progress_logger +}; diff --git a/lib/string.c b/lib/string.c index dbb66fe4d2..bad186586f 100644 --- a/lib/string.c +++ b/lib/string.c @@ -866,6 +866,15 @@ int strtobool(const char *str, int *val) } EXPORT_SYMBOL(strtobool); +bool strends(const char *str, const char *postfix) +{ + if (strlen(str) < strlen(postfix)) + return false; + + return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} +EXPORT_SYMBOL(strends); + /** * match_string - matches given string in an array * @array: array of strings diff --git a/lib/stringlist.c b/lib/stringlist.c index 719fecdaa4..fc86640b94 100644 --- a/lib/stringlist.c +++ b/lib/stringlist.c @@ -2,6 +2,7 @@ #include <xfuncs.h> #include <malloc.h> #include <errno.h> +#include <string.h> #include <stringlist.h> static int string_list_compare(struct list_head *a, struct list_head *b) @@ -95,6 +96,35 @@ int string_list_contains(struct string_list *sl, const char *str) return 0; } +char *string_list_join(const struct string_list *sl, const char *joinstr) +{ + struct string_list *entry; + size_t len = 0; + size_t joinstr_len = strlen(joinstr); + char *str, *next; + + string_list_for_each_entry(entry, sl) + len += strlen(entry->str) + joinstr_len; + + if (len == 0) + return strdup(""); + + str = malloc(len + 1); + if (!str) + return NULL; + + next = str; + + string_list_for_each_entry(entry, sl) { + next = stpcpy(next, entry->str); + next = stpcpy(next, joinstr); + } + + next[-joinstr_len] = '\0'; + + return str; +} + void string_list_print_by_column(struct string_list *sl) { int len = 0, num, i; diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 1d82adc733..237aab0c02 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -373,12 +373,21 @@ static char *pointer(const char *fmt, char *buf, const char *end, const void *pt return raw_pointer(buf, end, ptr, field_width, precision, flags); } +static char *errno_string(char *buf, const char *end, int field_width, int precision, int flags) +{ + return string(buf, end, strerror(errno), field_width, precision, flags); +} #else static char *pointer(const char *fmt, char *buf, const char *end, const void *ptr, int field_width, int precision, int flags) { return raw_pointer(buf, end, ptr, field_width, precision, flags); } + +static char *errno_string(char *buf, const char *end, int field_width, int precision, int flags) +{ + return buf; +} #endif /** @@ -569,6 +578,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) case 'u': break; + case 'm': + str = errno_string(str, end, field_width, precision, flags); + continue; + default: if (str < end) *str = '%'; diff --git a/net/Kconfig b/net/Kconfig index 1549c9af6b..3512055c45 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -35,7 +35,6 @@ config NET_SNTP config NET_FASTBOOT bool select BANNER - select FILE_LIST select FASTBOOT_BASE prompt "Android Fastboot support" help diff --git a/net/fastboot.c b/net/fastboot.c index 9082aa48f6..df388adc89 100644 --- a/net/fastboot.c +++ b/net/fastboot.c @@ -499,7 +499,6 @@ void fastboot_net_free(struct fastboot_net *fbn) struct fastboot_net *fastboot_net_init(struct fastboot_opts *opts) { struct fastboot_net *fbn; - const char *partitions = get_fastboot_partitions(); bool bbu = get_fastboot_bbu(); int ret; @@ -513,8 +512,7 @@ struct fastboot_net *fastboot_net_init(struct fastboot_opts *opts) fbn->fastboot.cmd_flash = opts->cmd_flash; ret = fastboot_generic_init(&fbn->fastboot, opts->export_bbu); } else { - fbn->fastboot.files = file_list_parse(partitions ? - partitions : ""); + fbn->fastboot.files = get_fastboot_partitions() ?: file_list_parse(""); ret = fastboot_generic_init(&fbn->fastboot, bbu); } if (ret) |