[U-Boot] [PATCH v6 23/27] cmd: mtdparts: add a generic 'mtdparts' parser

Miquel Raynal
2018-08-01T08:18:44Z

The current parser is very specific to U-Boot mtdparts implementation.
It does not use MTD structures like mtd_info and mtd_partition. Write
some kind of a wrapper around the current implementation to allow other
commands to benefit from this parsing in a user-friendly way.

This new command will allocate an mtd_partition array for each
successful call. This array must be freed after use by the caller.
The given 'mtdparts' buffer pointer will be moved forward to the next
MTD device (if any, it will point towards a '\0' character otherwise).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
---
cmd/mtdparts.c | 71 ++++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/partitions.h | 3 ++
2 files changed, 74 insertions(+)

diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index f26a761c99..27e84db0e4 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -78,6 +78,7 @@
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>

#if defined(CONFIG_CMD_NAND)
#include <linux/mtd/rawnand.h>
@@ -705,6 +706,76 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
return 0;
}

+int mtdparts_parse_part(struct mtd_info *parent, const char **_mtdparts,
+ struct mtd_partition **_parts, int *_nb_parts)
+{
+ const char *mtdparts = *_mtdparts;
+ struct part_info *part_legacy;
+ struct mtd_partition *parts;
+ int cur_off = 0, cur_sz = 0;
+ int nb_parts = 0;
+ char *names;
+ int ret, idx;
+
+ *_parts = NULL;
+ *_nb_parts = 0;
+
+ /* First, iterate over the partitions until we know their number */
+ while (mtdparts[0] != '\0' && mtdparts[0] != ';') {
+ ret = part_parse(mtdparts, &mtdparts, &part_legacy);
+ if (ret)
+ return ret;
+
+ nb_parts++;
+ free(part_legacy);
+ }
+
+ /* Allocate an array of partitions to give back to the caller */
+ parts = malloc((sizeof(*parts) + 20) * nb_parts);
+ names = (char *)&parts[nb_parts];
+ if (!parts) {
+ printf("Could not allocate enough space to save partitions meta-data\n");
+ return -ENOMEM;
+ }
+
+ /* Iterate again over each partition to save the data in our array */
+ for (idx = 0; idx < nb_parts; idx++) {
+ char *name;
+
+ ret = part_parse(*_mtdparts, _mtdparts, &part_legacy);
+ if (ret)
+ return ret;
+
+ name = &names[idx * 20];
+ strncpy(name, part_legacy->name, 20);
+ parts[idx].name = name;
+
+ parts[idx].size = part_legacy->size;
+ if (parts[idx].size == SIZE_REMAINING)
+ parts[idx].size = parent->size - cur_sz;
+ cur_sz += parts[idx].size;
+
+ parts[idx].offset = part_legacy->offset;
+ if (parts[idx].offset == OFFSET_NOT_SPECIFIED)
+ parts[idx].offset = cur_off;
+ cur_off += parts[idx].size;
+
+ parts[idx].mask_flags = part_legacy->mask_flags;
+ parts[idx].ecclayout = parent->ecclayout;
+
+ free(part_legacy);
+ }
+
+ /* Offset by one mtdparts to point to the next device if needed */
+ if (*_mtdparts[0] == ';')
+ _mtdparts++;
+
+ *_parts = parts;
+ *_nb_parts = nb_parts;
+
+ return 0;
+}
+
/**
* Check device number to be within valid range for given device type.
*
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index ce0e8dbee4..0cf26ca945 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -87,4 +87,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
int mtd_del_partition(struct mtd_info *master, int partno);
uint64_t mtd_get_device_size(const struct mtd_info *mtd);

+int mtdparts_parse_part(struct mtd_info *parent, const char **_mtdparts,
+ struct mtd_partition **_parts, int *_nb_parts);
+
#endif
--
2.14.1