summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-05-17 16:23:51 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-05-17 16:23:51 +0200
commitdee7a15dfaa640130d0b9bc289e5d55b358a2dbc (patch)
tree8ea7b1c341b1ea5453d1a3576fb238dc21edaa37
parentc5e0e697de769d0e78a00b1cb47fe864fade9974 (diff)
parent7ef2912d40b52202f563806fbffb9f615d2d2220 (diff)
downloadbarebox-dee7a15dfaa640130d0b9bc289e5d55b358a2dbc.tar.gz
barebox-dee7a15dfaa640130d0b9bc289e5d55b358a2dbc.tar.xz
Merge branch 'for-next/usb-gadget'
-rw-r--r--common/Kconfig15
-rw-r--r--common/Makefile3
-rw-r--r--common/bbu.c24
-rw-r--r--common/console_common.c20
-rw-r--r--common/fastboot.c28
-rw-r--r--common/file-list.c85
-rw-r--r--common/system-partitions.c44
-rw-r--r--common/usbgadget.c94
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/dfu.c3
-rw-r--r--drivers/usb/gadget/multi.c18
-rw-r--r--fs/fs.c6
-rw-r--r--include/bbu.h10
-rw-r--r--include/fastboot.h6
-rw-r--r--include/file-list.h12
-rw-r--r--include/linux/string.h10
-rw-r--r--include/param.h15
-rw-r--r--include/printk.h1
-rw-r--r--include/progress.h43
-rw-r--r--include/string.h1
-rw-r--r--include/stringlist.h1
-rw-r--r--include/system-partitions.h40
-rw-r--r--include/usb/gadget-multi.h1
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/parameter.c88
-rw-r--r--lib/show_progress.c28
-rw-r--r--lib/string.c9
-rw-r--r--lib/stringlist.c30
-rw-r--r--lib/vsprintf.c13
-rw-r--r--net/Kconfig1
-rw-r--r--net/fastboot.c4
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);
}
diff --git a/fs/fs.c b/fs/fs.c
index 73584d57e1..a9dbf1dd4e 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -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)