DFU, fastboot and incoming mass storage support all use file lists as input, but individually check syntax correctness only on use. A dedicated file list parameter would improve the user experience and makes the code using it easier to handle: the struct file_list can be passed around directly instead of having to parse it first on use. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- common/file-list.c | 47 +++++++++++++++++++++++ include/file-list.h | 3 ++ include/param.h | 15 ++++++++ include/stringlist.h | 1 + lib/parameter.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ lib/stringlist.c | 30 +++++++++++++++ 6 files changed, 184 insertions(+) diff --git a/common/file-list.c b/common/file-list.c index cd52b5e045de..924903cef7dc 100644 --- a/common/file-list.c +++ b/common/file-list.c @@ -6,6 +6,7 @@ #include <malloc.h> #include <fs.h> #include <file-list.h> +#include <stringlist.h> #include <linux/err.h> #define PARSE_DEVICE 0 @@ -109,6 +110,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; @@ -149,3 +169,30 @@ void file_list_free(struct file_list *files) free(files); } + +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; +} diff --git a/include/file-list.h b/include/file-list.h index 9a9edfa378f3..7264a3e2c628 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,6 +22,7 @@ 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, diff --git a/include/param.h b/include/param.h index 6aca1b481d92..4835be4d2518 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/stringlist.h b/include/stringlist.h index c5d6e70a367d..01491082ea02 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/lib/parameter.c b/lib/parameter.c index 173420c58a56..adc3c7cdea70 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/stringlist.c b/lib/stringlist.c index 719fecdaa456..fc86640b94a8 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; -- 2.29.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox