Skip to contentSkip to conversation

add support for GPT partition name manipulation

PATCH Superseded alison at peloton-tech.com 9 participants 116 messages May 21, 2017 – Aug 28, 2017

lore
Share & tools
lore
#0 lore raw

cover add support for GPT partition name manipulation

From: Alison Chaiken <[email protected]>

One way for userspace and the bootloader to exchange information about dynamic image selection is via the storage device partition table, as described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag. When no partition on a device is bootable since the kernel and U-Boot are stored elsewhere, the name field in the GPT partition table offers another logical place to store information. These patches allow users to easily modify GPT partition names via bootscripts that can select different images based on a boot-failure counter, or when userspace installs a software update.

These patches have been tested on a TI DRA7xx-based SOM with U-Boot 2015.07. The storage device is an eMMC.

Alison Chaiken (3):
GPT: add accessor function for disk GUID
GPT: read partition table from device into a data structure rename GPT partitions to detect boot failure

 cmd/gpt.c       | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 disk/part_efi.c |  31 ++++++
 include/part.h  |  24 ++++
 3 files changed, 392 insertions(+), 2 deletions(-)
Signature · 1 line
2.1.4
#1 lore raw

PATCH 1/3 GPT: add accessor function for disk GUID

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

---
 cmd/gpt.c       | 29 ++++++++++++++++++++++++++++-
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 include/part.h  | 15 +++++++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)
cmd/gpt.c +28 -1
index 3e98821..814cb11 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return 1;
+
+	if (namestr != NULL)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return 0;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
 	int dev = 0;
-	char *ep;
+	char *ep, *varname = NULL;
 	struct blk_desc *blk_dev_desc = NULL;
 
 	if (argc < 4 || argc > 5)
@@ -436,6 +453,9 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5) strcpy(varname, argv[4]);
+		return do_disk_guid(blk_dev_desc, varname);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +478,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +31 -0
index 1b7ba27..de35c9b 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -1;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
include/part.h +15 -0
index 83bce05..69143bb 100644
@@ -367,6 +367,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
Signature · 1 line
2.1.4
#2 lore raw

PATCH 1/3 GPT: add accessor function for disk GUID

Quoted 8 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Overall looks good, a few style things:

cmd/gpt.c static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) · line 411

Quoted 2 lines
cmd/gpt.c +2 -0
+	if (namestr != NULL)
+		setenv(namestr, disk_guid);

You can just if (namestr) here

[snip]

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 457

Quoted 2 lines
cmd/gpt.c +2 -0
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5) strcpy(varname, argv[4]);

Go ahead and do this on multiple lines please. Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/649a855f/attachment.sig>
#3 lore raw

PATCH 2/3 GPT: read partition table from device into a data structure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   9 +++++
 2 files changed, 122 insertions(+)
cmd/gpt.c +113 -0
index 814cb11..128c895 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,112 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	/*
+	 * 33 rather than 32, as each string must be null-terminated;
+	 * other extract_val() above will fail.
+	 */
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, 33);
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, 33);
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN + 1);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */
+	int valid_parts = 1, p, ret = 0;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
+			return -1;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -1;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -456,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if (strcmp(argv[1], "guid") == 0) {
 		if (argc == 5) strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -478,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +9 -0
index 69143bb..87a9818 100644
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -46,6 +47,8 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define MAX_SEARCH_PARTITIONS 16
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
 	lbaint_t	size;	/* number of blocks in partition	*/
@@ -64,6 +67,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#4 lore raw

PATCH 2/3 GPT: read partition table from device into a data structure

Quoted 7 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

[snip]

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 183

Quoted 6 lines
cmd/gpt.c +6 -0
+	/*
+	 * 33 rather than 32, as each string must be null-terminated;
+	 * other extract_val() above will fail.
+	 */
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, 33);
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, 33);

This isn't right. We have name[32]/type[32] so we're overflowing. I'm not quite sure where 32 came from and if we should be defining a name for it as well. But to make sure it is null-terminated we should be here memset'ing after malloc.

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 188

Quoted 5 lines
cmd/gpt.c +5 -0
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN + 1);
+#endif

Then this should just be copying UUID_STR_LEN over.

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 244

Quoted 4 lines
cmd/gpt.c +4 -0
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -1;

We should return something from errno here rather than -1. Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/569fea78/attachment.sig>
#5 lore raw

PATCH 3/3 rename GPT partitions to detect boot failure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it renames it failed’ and renames the ‘backup’ partition as ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
via u-boot. Partitions can go to ‘backup’ only from ‘primary’ and vice-versa, only via Linux. Partitions go to ‘candidate’ from ‘primary’ or ‘backup’ only via u-boot. Only system update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/gpt.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 201 insertions(+), 6 deletions(-)
cmd/gpt.c +201 -6
index 128c895..f2c32ae 100644
@@ -21,6 +21,9 @@
 #include <memalign.h>
 #include <linux/compat.h>
 
+/* ONEMIB is 2**20 */
+#define ONEMIB 1024*1024
+
 static LIST_HEAD(disk_partitions);
 
 /**
@@ -114,7 +117,6 @@ static char *extract_val(const char *str, const char *key)
 			break;
 		}
 	}
-
 	free(strcopy);
 
 	return new;
@@ -158,6 +160,7 @@ static void del_gpt_info(void)
 {
 	struct list_head *pos = &disk_partitions;
 	struct disk_part *curr;
+
 	while (!list_empty(pos)) {
 		curr = list_entry(pos->next, struct disk_part, list);
 		list_del(pos->next);
@@ -165,6 +168,11 @@ static void del_gpt_info(void)
 	}
 }
 
+/*
+ * The number '33' comes from the '32' in the definition of disk_partition_t
+ * in include/part.h.   That file has '37' rather than UUID_STR_LEN + 1, from
+ * include/uuid.h
+ */
 static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 {
 	struct disk_part *newpart;
@@ -191,16 +199,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, ONEMIB);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -212,6 +237,89 @@ static void print_gpt_info(void)
 	}
 }
 
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + 33);
+	/* 17 because partstr below is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen ++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[16];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over 'partitions='.
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		/*
+		 * name is 32 chars long, per definition of disk_partition_t in part.h,
+		 * plus one extra byte for NULL
+		 */
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, 33);
+
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, 17);
+
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, 17);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -223,8 +331,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -241,7 +352,6 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	if (!valid_parts) {
 		printf("** No valid partitions found **\n");
 		del_gpt_info();
-		return -1;
 	}
 	return --valid_parts;
 }
@@ -295,10 +405,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
 	val = extract_val(str, "uuid_disk");
+
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
@@ -312,6 +425,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		if (extract_env(val, &p))
 			p = val;
 		*str_disk_guid = strdup(p);
+
 		free(val);
 		/* Move s to first partition */
 		strsep(&s, ";");
@@ -524,6 +638,83 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return 0;
 }
 
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -567,6 +758,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, varname);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -591,6 +784,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" gpt verify mmc 0 $partitions\n"
 	" read <interface> <dev>\n"
 	"    - read GPT into a data structure for manipulation\n"
+	" flip <interface> <dev>\n"
+	"    - exchange 'primary' and 'backup' partition names in GPT"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
Signature · 1 line
2.1.4
#6 lore raw

PATCH 3/3 rename GPT partitions to detect boot failure

Quoted 5 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

[snip]

Quoted 4 lines
---
 cmd/gpt.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 201 insertions(+), 6 deletions(-)

There's some whitespace-only chunks, please drop. Also:

[snip]

cmd/gpt.c line 25

Quoted 2 lines
cmd/gpt.c +2 -0
+/* ONEMIB is 2**20 */
+#define ONEMIB 1024*1024

SZ_1MB from <linux/sizes.h>

Quoted 5 lines

+/*
+ * The number '33' comes from the '32' in the definition of disk_partition_t
+ * in include/part.h. That file has '37' rather than UUID_STR_LEN + 1, from
+ * include/uuid.h
+ */

Lets update include/part.h in a new patch earlier in the series, possibly as part of addressing the problems I mention with the previous patch. Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/8de83231/attachment.sig>
#7 lore raw

PATCH 3/3 rename GPT partitions to detect boot failure

In reply to alison at peloton-tech.com
Quoted 38 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it renames it failed’ and renames the ‘backup’ partition as ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
via u-boot. Partitions can go to ‘backup’ only from ‘primary’ and vice-versa, only via Linux. Partitions go to ‘candidate’ from ‘primary’ or ‘backup’ only via u-boot. Only system update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/gpt.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 201 insertions(+), 6 deletions(-)
cmd/gpt.c +0 -0
index 128c895..f2c32ae 100644

cmd/gpt.c line 26

Quoted 6 lines
cmd/gpt.c +2 -0
@@ -21,6 +21,9 @@
 #include <memalign.h>
 #include <linux/compat.h>
 
+/* ONEMIB is 2**20 */
+#define ONEMIB 1024*1024
 

'()' are missing around the expression!
But anyway, there is no need to reinvent the wheel, since SZ_1M exists in include/linux/sizes.h.

Quoted 83 lines
cmd/gpt.c +1 -0
+
 static LIST_HEAD(disk_partitions);
 

/**

cmd/gpt.c +36 -3
@@ -114,7 +117,6 @@ static char *extract_val(const char *str, const char *key)
 			break;
 		}
 	}
-
 	free(strcopy);
 
 	return new;
@@ -158,6 +160,7 @@ static void del_gpt_info(void)
 {
 	struct list_head *pos = &disk_partitions;
 	struct disk_part *curr;
+
 	while (!list_empty(pos)) {
 		curr = list_entry(pos->next, struct disk_part, list);
 		list_del(pos->next);
@@ -165,6 +168,11 @@ static void del_gpt_info(void)
 	}
 }
 
+/*
+ * The number '33' comes from the '32' in the definition of disk_partition_t
+ * in include/part.h.   That file has '37' rather than UUID_STR_LEN + 1, from
+ * include/uuid.h
+ */
 static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 {
 	struct disk_part *newpart;
@@ -191,16 +199,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, ONEMIB);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -212,6 +237,89 @@ static void print_gpt_info(void)
 	}
 }
 
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;

cmd/gpt.c static void print_gpt_info(void) · line 260

Quoted 10 lines
cmd/gpt.c +9 -0
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + 33);
+	/* 17 because partstr below is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen ++;
 

partlistlen++;

Quoted 33 lines
cmd/gpt.c +33 -0
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[16];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over 'partitions='.
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");

cmd/gpt.c static void print_gpt_info(void)

Quoted 10 lines
cmd/gpt.c +9 -0
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		/*
+		 * name is 32 chars long, per definition of disk_partition_t in part.h,
+		 * plus one extra byte for NULL
+		 */
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, 33);
 

unnecessary cast. The same holds for all the other (const char *) casts in this patch.

Quoted 85 lines
cmd/gpt.c +21 -0
+
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, 17);
+
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, 17);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+
 /*

* read partition info into disk_partitions list where
* it can be printed or modified

cmd/gpt.c +22 -3
@@ -223,8 +331,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -241,7 +352,6 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	if (!valid_parts) {
 		printf("** No valid partitions found **\n");
 		del_gpt_info();
-		return -1;
 	}
 	return --valid_parts;
 }
@@ -295,10 +405,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
 	val = extract_val(str, "uuid_disk");
+
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
@@ -312,6 +425,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		if (extract_env(val, &p))
 			p = val;
 		*str_disk_guid = strdup(p);
+
 		free(val);
 		/* Move s to first partition */
 		strsep(&s, ";");
@@ -524,6 +638,83 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return 0;
 }
 
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 663

Quoted 10 lines
cmd/gpt.c +9 -0
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
 

Useless cast.

Lothar Waßmann

Signature · 31 lines
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
#8 lore raw

cover add support for GPT partition name manipulation

In reply to alison at peloton-tech.com
Quoted 24 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

One way for userspace and the bootloader to exchange information about dynamic image selection is via the storage device partition table, as described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag. When no partition on a device is bootable since the kernel and U-Boot are stored elsewhere, the name field in the GPT partition table offers another logical place to store information. These patches allow users to easily modify GPT partition names via bootscripts that can select different images based on a boot-failure counter, or when userspace installs a software update.

These patches have been tested on a TI DRA7xx-based SOM with U-Boot 2015.07. The storage device is an eMMC.

Alison Chaiken (3):
GPT: add accessor function for disk GUID
GPT: read partition table from device into a data structure rename GPT partitions to detect boot failure

Quoted 4 lines
 cmd/gpt.c       | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 disk/part_efi.c |  31 ++++++
 include/part.h  |  24 ++++
 3 files changed, 392 insertions(+), 2 deletions(-)

Interesting. Adding Lukasz for comments as well. I was thinking perhaps the final patch in the series might want to be guarded with some Kconfig option as it's rather specific to this update mechanism and probably causes a noticeable size increase due to the strings. Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/8de5c53d/attachment.sig>
#9 lore raw

v2 cover add support for GPT partition name manipulation

From: Alison Chaiken <[email protected]>

One way for userspace and the bootloader to exchange information about dynamic image selection is via the storage device partition table, as described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag. When no partition on a device is bootable since the kernel and U-Boot are stored elsewhere, the name field in the GPT partition table offers another logical place to store information. These patches allow users to easily modify GPT partition names via bootscripts that can select different images based on a boot-failure counter, or when userspace installs a software update.

These patches have been tested on a TI DRA7xx-based SOM with U-Boot 2015.07. The storage device is an eMMC.

Significant changes since v1:
-- Put the gpt_flip() function and auxiliary ones inside a new
CONFIG_CMD_GPT_FLIP option that depends on CMD_GPT.
-- Replace intentional overwriting of name and type string arrays with
memset() instead.
-- Move part.h changes earlier in the patchset.
-- Add a few lines to README.gpt about the new gpt subcommands.

Added a few simple patches to do the following:
-- Replace remaining occurrences of '37' with UUID_STR_LEN+1; -- Introduce new macros to get rid of the similar '32'; -- fix a smaller error in doc/README.gpt.

There are also some fixups of whitespace and formatting errors (plus usual inevitable addition of new ones).

To do in future:
-- Add support for preserving the type flag for partitions. The u-boot
version on which this patchset is based did not have this feature, and it's easy to add, but I need to figure how to test it first.

Alison Chaiken (6):
EFI: replace number with UUID_STR_LEN macro
disk_partition: introduce macros for description string lengths
GPT: add accessor function for disk GUID
GPT: read partition table from device into a data structure rename GPT partitions to detect boot failure
GPT: fix error in partitions string doc

 cmd/Kconfig     |   7 ++
 cmd/gpt.c       | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 disk/part_efi.c |  33 +++++-
 doc/README.gpt  |  24 ++++-
 include/part.h  |  35 +++++-
 5 files changed, 410 insertions(+), 11 deletions(-)
Signature · 1 line
2.1.4
#10 lore raw

PATCH v2 1/6 EFI: replace number with UUID_STR_LEN macro

From: Alison Chaiken <[email protected]>

---
 disk/part_efi.c | 2 +-
 include/part.h  | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)
disk/part_efi.c +1 -1
index 1b7ba27..20d33ef 100644
@@ -183,7 +183,7 @@ void part_print_efi(struct blk_desc *dev_desc)
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
 	gpt_entry *gpt_pte = NULL;
 	int i = 0;
-	char uuid[37];
+	char uuid[UUID_STR_LEN + 1];
 	unsigned char *uuid_bin;
 
 	/* This function validates AND fills in the GPT header and PTE */
include/part.h +3 -2
index 83bce05..6ace09f 100644
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <uuid.h>
 
 struct block_drvr {
 	char *name;
@@ -54,10 +55,10 @@ typedef struct disk_partition {
 	uchar	type[32];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-	char	uuid[37];	/* filesystem UUID as string, if exists	*/
+	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
 #endif
 #ifdef CONFIG_PARTITION_TYPE_GUID
-	char	type_guid[37];	/* type GUID as string, if exists	*/
+	char	type_guid[UUID_STR_LEN + 1];	/* type GUID as string, if exists	*/
 #endif
 #ifdef CONFIG_DOS_PARTITION
 	uchar	sys_ind;	/* partition type 			*/
Signature · 1 line
2.1.4
#11 lore raw

PATCH v2 1/6 EFI: replace number with UUID_STR_LEN macro

Quoted 3 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170530/17d50781/attachment.sig>
#12 lore raw

PATCH v2 1/6 EFI: replace number with UUID_STR_LEN macro

In reply to alison at peloton-tech.com

Hi Alison,

Quoted 3 lines

From: Alison Chaiken <[email protected]>

Quoted 46 lines
---
 disk/part_efi.c | 2 +-
 include/part.h  | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)
disk/part_efi.c +1 -1
index 1b7ba27..20d33ef 100644
@@ -183,7 +183,7 @@ void part_print_efi(struct blk_desc *dev_desc)
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
 dev_desc->blksz); gpt_entry *gpt_pte = NULL;
 	int i = 0;
-	char uuid[37];
+	char uuid[UUID_STR_LEN + 1];
 	unsigned char *uuid_bin;
 
 	/* This function validates AND fills in the GPT header and

PTE */ diff --git a/include/part.h b/include/part.h index 83bce05..6ace09f 100644

include/part.h +1 -0
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <uuid.h>
 
 struct block_drvr {
 	char *name;
@@ -54,10 +55,10 @@ typedef struct disk_partition {
 	uchar	type[32];	/* string type

description */ int bootable; /*
Active/Bootable flag is set */ #if
CONFIG_IS_ENABLED(PARTITION_UUIDS)

include/part.h +0 -1
-	char	uuid[37];	/* filesystem UUID as string,

if exists */

include/part.h +1 -0
+	char	uuid[UUID_STR_LEN + 1];	/* filesystem

UUID as string, if exists */ #endif
#ifdef CONFIG_PARTITION_TYPE_GUID

include/part.h +0 -1
-	char	type_guid[37];	/* type GUID as string, if

exists */

include/part.h +1 -0
+	char	type_guid[UUID_STR_LEN + 1];	/* type GUID

as string, if exists */ #endif
#ifdef CONFIG_DOS_PARTITION
uchar sys_ind; /* partition type

Quoted 1 line
			*/

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#13 lore raw

PATCH v2 2/6 disk_partition: introduce macros for description string lengths

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

---
 include/part.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
include/part.h +5 -2
index 6ace09f..87b1111 100644
@@ -47,12 +47,15 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define PART_NAME_LEN 32
+#define PART_TYPE_LEN 32
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
 	lbaint_t	size;	/* number of blocks in partition	*/
 	ulong	blksz;		/* block size in bytes			*/
-	uchar	name[32];	/* partition name			*/
-	uchar	type[32];	/* string type description		*/
+	uchar	name[PART_NAME_LEN];	/* partition name			*/
+	uchar	type[PART_TYPE_LEN];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
Signature · 1 line
2.1.4
#14 lore raw

PATCH v2 2/6 disk_partition: introduce macros for description string lengths

Hi Alison,

Quoted 30 lines

From: Alison Chaiken <[email protected]>

---
 include/part.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
include/part.h +3 -0
index 6ace09f..87b1111 100644
@@ -47,12 +47,15 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define PART_NAME_LEN 32
+#define PART_TYPE_LEN 32
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in

partition */ lbaint_t size; /* number of blocks
in partition */ ulong blksz; /* block
size in bytes */

include/part.h +0 -1
-	uchar	name[32];	/* partition

name */

include/part.h +0 -1
-	uchar	type[32];	/* string type

description */

include/part.h +1 -0
+	uchar	name[PART_NAME_LEN];	/* partition

name */

include/part.h +1 -0
+	uchar	type[PART_TYPE_LEN];	/* string type
Quoted 4 lines

description */ int bootable; /*
Active/Bootable flag is set */ #if
CONFIG_IS_ENABLED(PARTITION_UUIDS) char uuid[UUID_STR_LEN +
1]; /* filesystem UUID as string, if exists */

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#15 lore raw

PATCH v2 2/6 disk_partition: introduce macros for description string lengths

In reply to alison at peloton-tech.com
Quoted 3 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170531/f0de67f3/attachment.sig>
#16 lore raw

PATCH v2 3/6 GPT: add accessor function for disk GUID

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

---
 cmd/gpt.c       | 30 +++++++++++++++++++++++++++++-
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 77 insertions(+), 2 deletions(-)
cmd/gpt.c +29 -1
index 3e98821..3b7d929 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return 1;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return 0;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
 	int dev = 0;
-	char *ep;
+	char *ep, *varname = NULL;
 	struct blk_desc *blk_dev_desc = NULL;
 
 	if (argc < 4 || argc > 5)
@@ -436,6 +453,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5)
+		       strcpy(varname, argv[4]);
+		return do_disk_guid(blk_dev_desc, varname);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +479,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +31 -0
index 20d33ef..ff9f408 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -1;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
doc/README.gpt +2 -1
index 3fcd835..c0779a4 100644
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
include/part.h +15 -0
index 87b1111..16c4a46 100644
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
Signature · 1 line
2.1.4
#17 lore raw

PATCH v2 3/6 GPT: add accessor function for disk GUID

Quoted 22 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

---
 cmd/gpt.c       | 30 +++++++++++++++++++++++++++++-
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 77 insertions(+), 2 deletions(-)
cmd/gpt.c +0 -0
index 3e98821..3b7d929 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }

cmd/gpt.c static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) · line 409

Quoted 10 lines
cmd/gpt.c +9 -0
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return 1;
+

Since you are calling this function from a CMD handler and passing its return value as the CMD handlers exit code this should be:

		return CMD_RET_FAILURE;

cmd/gpt.c static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)

Quoted 7 lines
cmd/gpt.c +6 -0
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return 0;
 

... and this:

	return CMD_RET_SUCCESS;
Quoted 13 lines
cmd/gpt.c +1 -1
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
 	int dev = 0;
-	char *ep;
+	char *ep, *varname = NULL;
 	struct blk_desc *blk_dev_desc = NULL;
 
 	if (argc < 4 || argc > 5)

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 459

Quoted 7 lines
cmd/gpt.c +3 -0
@@ -436,6 +453,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5)
+		       strcpy(varname, argv[4]);
 

You didn't allocate any memory for varname and copy the argument string to a NULL pointer!
Maybe use strdup() and free varname after use?

Quoted 30 lines
cmd/gpt.c +1 -0
+		return do_disk_guid(blk_dev_desc, varname);
 	} else {
 		return CMD_RET_USAGE;
cmd/gpt.c +7 -0
 	}
@@ -458,4 +479,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +6 -0
index 20d33ef..ff9f408 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{

disk/part_efi.c static void prepare_backup_gpt_header(gpt_header *gpt_h) · line 196

Quoted 10 lines
disk/part_efi.c +9 -0
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
 

useless '()'

disk/part_efi.c static void prepare_backup_gpt_header(gpt_header *gpt_h) · line 199

Quoted 4 lines
disk/part_efi.c +4 -0
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -1;

return -EINVAL;?

disk/part_efi.c static void prepare_backup_gpt_header(gpt_header *gpt_h)

Quoted 8 lines
disk/part_efi.c +7 -0
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
 

disk_guid.b is of type u8 which is the same as unsigned char. No need for a type cast here (and the () around gpt_head->... are unnecessary).

Quoted 48 lines
disk/part_efi.c +5 -0
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)

{

disk/part_efi.c +0 -0
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
doc/README.gpt +2 -1
index 3fcd835..c0779a4 100644
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
include/part.h +15 -0
index 87b1111..16c4a46 100644
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
Signature · 9 lines
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
#18 lore raw

v3 cover add support for GPT partition name manipulation

From: Alison Chaiken <[email protected]>

One way for userspace and the bootloader to exchange information about dynamic image selection is via the storage device partition table, as described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag. When no partition on a device is bootable since the kernel and U-Boot are stored elsewhere, the name field in the GPT partition table offers another logical place to store information. These patches allow users to easily modify GPT partition names via bootscripts that can select different images based on a boot-failure counter, or when userspace installs a software update.

These patches have been (re)tested on a TI DRA7xx-based SOM with U-Boot 2015.07. The storage device is an eMMC.

Significant changes since v2:
-- Got rid of the need to allocate memory for the GUID string in
do_gpt();
-- Fixed the problems with string NULL termination in
allocate_disk_part();
-- Removed duplicate definition of MAX_SEARCH_PARTITIONS from
disk/part.c and increased the value in include/part.h to 64;
-- Improved the commit message for "rename GPT partitions to detect
boot failure" to better describe the version of the patch I submitted;
-- Fixed numerous small problems with function return values.

Significant changes since v1:
-- Put the gpt_flip() function and auxiliary ones inside a new
CONFIG_CMD_GPT_FLIP option that depends on CMD_GPT.
-- Replace intentional overwriting of name and type string arrays with
memset() instead.
-- Move part.h changes earlier in the patchset.
-- Add a few lines to README.gpt about the new gpt subcommands.

Added a few simple patches to do the following:
-- Replace remaining occurrences of '37' with UUID_STR_LEN+1; -- Introduce new macros to get rid of the similar '32'; -- fix a smaller error in doc/README.gpt.

There are also some fixups of whitespace and formatting errors (plus usual inevitable addition of new ones).

To do in future:
-- Add support for preserving the type flag for partitions. The u-boot
version on which this patchset is based did not have this feature, and it's easy to add, but I need to figure how to test it first.

-- Add tests for the new gpt commands to the sandbox.

Alison Chaiken (5):
GPT: add accessor function for disk GUID
partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
GPT: read partition table from device into a data structure rename GPT partitions to detect boot failure
GPT: fix error in partitions string doc

 cmd/Kconfig     |   7 ++
 cmd/gpt.c       | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 disk/part.c     |   1 -
 disk/part_efi.c |  31 ++++++
 doc/README.gpt  |  24 ++++-
 include/part.h  |  23 ++++
 6 files changed, 398 insertions(+), 6 deletions(-)
Signature · 1 line
2.1.4
#19 lore raw

PATCH v3 1/5 GPT: add accessor function for disk GUID

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)
cmd/gpt.c +26 -0
index 3e98821..4d00a35 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		return do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +477,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +31 -0
index 20d33ef..71c3cb3 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -EINVAL;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = gpt_head->disk_guid.b;
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
doc/README.gpt +2 -1
index 3fcd835..c0779a4 100644
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
include/part.h +15 -0
index 87b1111..16c4a46 100644
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
Signature · 1 line
2.1.4
#20 lore raw

PATCH v3 1/5 GPT: add accessor function for disk GUID

Hi,

Quoted 29 lines · On Fri, 2 Jun 2017 19:22:30 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)
cmd/gpt.c +6 -0
index 3e98821..4d00a35 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);

cmd/gpt.c static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) · line 416

Quoted 10 lines
cmd/gpt.c +9 -0
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
 

For consistency this should be:

	return CMD_RET_SUCCESS;

but see below.

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 460

Quoted 12 lines
cmd/gpt.c +2 -0
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		return do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}

IMO you should use the existing error handling infrastructure lateron in this file and just assign the return value of the subcommand handlers to 'ret' and let the existing code sort out the return code of this function (just like the gpt_verify() call above does it).

Lothar Waßmann

#21 lore raw

PATCH v5 1/3 GPT: add accessor function for disk GUID

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Changes since v4:
-- Made do_disk_guid() return 0 upon success so that now, in the
sandbox, u-boot prints a "success!" exit message.

---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)
cmd/gpt.c +26 -0
index 3e98821..65fb80b 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +477,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +31 -0
index 20d33ef..71c3cb3 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -EINVAL;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = gpt_head->disk_guid.b;
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
doc/README.gpt +2 -1
index 3fcd835..c0779a4 100644
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
include/part.h +15 -0
index 87b1111..16c4a46 100644
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
Signature · 1 line
2.1.4
#22 lore raw

PATCH v5 1/3 GPT: add accessor function for disk GUID

Quoted 7 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Quoted 5 lines

Changes since v4:
-- Made do_disk_guid() return 0 upon success so that now, in the
sandbox, u-boot prints a "success!" exit message.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170611/67a2326e/attachment.sig>
#23 lore raw

PATCH v3 2/5 partitions: increase MAX_SEARCH_PARTITIONS and move to part.h

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd directory can find it. At the same time, increase the value to 64 since some operating systems use many, and the resources consumed by a larger value are minimal.

---
 disk/part.c    | 1 -
 include/part.h | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)
disk/part.c +0 -1
index 491b02d..e640a55 100644
@@ -388,7 +388,6 @@ cleanup:
 
 #define PART_UNSPECIFIED -2
 #define PART_AUTO -1
-#define MAX_SEARCH_PARTITIONS 16
 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 			     struct blk_desc **dev_desc,
 			     disk_partition_t *info, int allow_whole_dev)
include/part.h +1 -0
index 16c4a46..c41aa6a 100644
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 64
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
Signature · 1 line
2.1.4
#24 lore raw

PATCH v3 2/5 partitions: increase MAX_SEARCH_PARTITIONS and move to part.h

Hi Alison,

Quoted 37 lines

From: Alison Chaiken <[email protected]>

Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd directory can find it. At the same time, increase the value to 64 since some operating systems use many, and the resources consumed by a larger value are minimal.

---
 disk/part.c    | 1 -
 include/part.h | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)
disk/part.c +0 -1
index 491b02d..e640a55 100644
@@ -388,7 +388,6 @@ cleanup:
 
 #define PART_UNSPECIFIED -2
 #define PART_AUTO -1
-#define MAX_SEARCH_PARTITIONS 16
 int blk_get_device_part_str(const char *ifname, const char
 *dev_part_str, struct blk_desc **dev_desc,
 			     disk_partition_t *info, int

allow_whole_dev) diff --git a/include/part.h b/include/part.h index 16c4a46..c41aa6a 100644

include/part.h +1 -0
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 64
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in
Quoted 1 line

partition */

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#25 lore raw

PATCH v3 3/5 GPT: read partition table from device into a data structure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 119 insertions(+)
cmd/gpt.c +112 -0
index 4d00a35..5c2651f 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && valid_parts >= 2)
+			return -ENODEV;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +563,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		return do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +587,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +7 -0
index c41aa6a..0cd803a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#26 lore raw

PATCH v3 3/5 GPT: read partition table from device into a data structure

Hi,

Quoted 100 lines · On Fri, 2 Jun 2017 19:22:32 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 119 insertions(+)
cmd/gpt.c +73 -0
index 4d00a35..5c2651f 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 236

Quoted 10 lines
cmd/gpt.c +9 -0
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && valid_parts >= 2)
+			return -ENODEV;
 

del_gpt_info()? This calls for a common error exit which does the cleanup.

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 247

Quoted 12 lines
cmd/gpt.c +12 -0
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+

Lothar Waßmann

#27 lore raw

PATCH v5 2/3 GPT: read partition table from device into a data structure

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

Changes since v4:
-- Made do_get_gpt_info() return 0 upon success so that now, in the
sandbox, u-boot prints a "success!" exit message.
-- Created a single exit point for get_gpt_info(), with the
result that after an error, del_gpt_info() always removes the list.

---
 cmd/gpt.c      | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 127 insertions(+)
cmd/gpt.c +120 -0
index 65fb80b..669031f8 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,119 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;
+ out:
+	if (valid_parts >= 2)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +571,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +595,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +7 -0
index c41aa6a..0cd803a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#28 lore raw

PATCH v5 2/3 GPT: read partition table from device into a data structure

Quoted 6 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

Quoted 8 lines

Changes since v4:
-- Made do_get_gpt_info() return 0 upon success so that now, in the
sandbox, u-boot prints a "success!" exit message.
-- Created a single exit point for get_gpt_info(), with the
result that after an error, del_gpt_info() always removes the list.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170611/99ef27ba/attachment.sig>
#29 lore raw

PATCH v3 3/5 GPT: read partition table from device into a data structure

In reply to alison at peloton-tech.com

Hi,

Quoted 139 lines · On Fri, 2 Jun 2017 19:22:32 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 119 insertions(+)
cmd/gpt.c +108 -0
index 4d00a35..5c2651f 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && valid_parts >= 2)
+			return -ENODEV;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 568

Quoted 6 lines
cmd/gpt.c +2 -0
@@ -455,6 +563,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		return do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 

See my comment to your patch 1/5

Quoted 28 lines
cmd/gpt.c +0 -0
 	} else {
 		return CMD_RET_USAGE;
cmd/gpt.c +2 -0
 	}
@@ -477,6 +587,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +1 -0
index c41aa6a..0cd803a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;

include/part.h typedef struct disk_partition { · line 81

Quoted 10 lines
include/part.h +6 -0
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**

Lothar Waßmann

#30 lore raw

PATCH v3 4/5 rename GPT partitions to detect boot failure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 215 insertions(+), 4 deletions(-)
cmd/Kconfig +7 -0
index 6f75b86..8b925e5 100644
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +195 -4

253 lines not on this page · raw message

doc/README.gpt +13 -0
index c0779a4..e29b188 100644
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
Signature · 1 line
2.1.4
#31 lore raw

PATCH v3 4/5 rename GPT partitions to detect boot failure

Hi,

Quoted 104 lines · On Fri, 2 Jun 2017 19:22:33 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 215 insertions(+), 4 deletions(-)
cmd/Kconfig +7 -0
index 6f75b86..8b925e5 100644
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +27 -2
index 5c2651f..f6968de 100644
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -190,16 +191,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -211,6 +229,85 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");

cmd/gpt.c static void print_gpt_info(void) · line 248

Quoted 10 lines
cmd/gpt.c +9 -0
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
 

NO! The size of partstr in create_gpt_partitions_list() is:
| char partstr[PART_NAME_LEN + 1];
which happens to be defined as:

include/part.h +0 -0
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
                       ^^
 #define PART_TYPE_LEN 32
 

cmd/gpt.c static void print_gpt_info(void) · line 251

Quoted 3 lines
cmd/gpt.c +2 -0
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
 

Never use magic numbers in code, but use appropriate #define's!

Quoted 8 lines
cmd/gpt.c +4 -0
@@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 641

Quoted 10 lines
cmd/gpt.c +10 -0
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;

AGAIN: You are passing the return value of this function back to the caller of the CMD handler do_gpt() which expects a return value of CMD_RET_FAILURE or CMD_RET_SUCCESS, not an arbitrary negative value.

Quoted 70 lines
cmd/gpt.c +66 -0
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 754

Quoted 8 lines
cmd/gpt.c +4 -0
@@ -565,6 +747,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
+#endif
 

See my comment to your patch 1/5.

Lothar Waßmann

#32 lore raw

PATCH v5 3/3 rename GPT partitions to detect boot failure

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Changes since v4:
-- Changed the erroneous '17' values in calc_parts_list_len() to
match the definition of struct disk_partition in part.h.
-- Modified do_gpt() so that the 'gpt flip' command prints
"success!" or "error!" on exit.

---
 cmd/Kconfig    |   7 +++
 cmd/gpt.c      | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 206 insertions(+), 4 deletions(-)
cmd/Kconfig +7 -0
index 270cff6..880ca97 100644
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +186 -4

244 lines not on this page · raw message

doc/README.gpt +13 -0
index c0779a4..e29b188 100644
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
Signature · 1 line
2.1.4
#33 lore raw

PATCH v5 3/3 rename GPT partitions to detect boot failure

Dear Alison,

Quoted 5 lines · In message <[email protected]> you…

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

Quoted 8 lines

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it tries to boot the ‘backup’ partition.

I think you are talking about two parts here, and I strongly feel these should be kept separate.

The first part is support for renaming GPT partitions. The idea is clean, but should it not rather be kept general and let the user provide the new name as argument, i. e. implement a generic "gpt rename" command instead of a hard-wired "gpt flip"?

The second part is the flipping of the partition names. This is in my opinion policy, and should also not be hardwaired into this command, but left to the user. Maybe I do nmot want to fall back to the ‘backup’ partition after a single boot attempt, but instead try other things first, like booting another kernel or another device tree blob?

I feel this should be not so much hardwired, but leave more freedom for the user's creativity.

What do you think?

Best regards,

Wolfgang Denk

Signature · 6 lines
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
...computer hardware progress is so fast. No other  technology  since
civilization  began  has seen six orders of magnitude in performance-
price gain in 30 years.                             - Fred Brooks, Jr.
#34 lore raw

PATCH v5 3/3 rename GPT partitions to detect boot failure

Quoted 15 lines · Wolfgang Denk

I think you are talking about two parts here, and I strongly feel these should be kept separate.

The first part is support for renaming GPT partitions. The idea is clean, but should it not rather be kept general and let the user provide the new name as argument, i. e. implement a generic "gpt rename" command instead of a hard-wired "gpt flip"?

The second part is the flipping of the partition names. This is in my opinion policy, and should also not be hardwaired into this command, but left to the user. Maybe I do nmot want to fall back to the ‘backup’ partition after a single boot attempt, but instead try other things first, like booting another kernel or another device tree blob?

Quoted 3 lines

I feel this should be not so much hardwired, but leave more freedom for the user's creativity.

Lukasz has already made similar suggestions. In the following message is
a new version which attempts to implement them.

Thanks to Lothar and Lukasz for all their help.

Best wishes,
Alison Chaiken
Peloton Technology

#35 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

In reply to Wolfgang Denk

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode prints a warning if no matching partition names are found. If only one matching name of a provided pair is found, it renames the matching partitions to the new name.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Changes since v5:
-- The former 'gpt flip' is now 'gpt swap', which takes the two
arbitrary partition names it exchanges as command-line input.
-- A new command, 'gpt rename', now allows renaming of single,
specified partitions.
-- Updated README.gpt to reflect the changes.

---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)
cmd/Kconfig +8 -0
index 412bf24..7b262de 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +234 -5

299 lines not on this page · raw message

doc/README.gpt +19 -1
index 6c5ab78..d3db8bc 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
Signature · 1 line
2.1.4
#36 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Quoted 9 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode prints a warning if no matching partition names are found. If only one matching name of a provided pair is found, it renames the matching partitions to the new name.

So in the case where 'gpt swap partA partB' is used and partB doesn't exist, it's the same as 'gpt rename partA partB' ? That seems like it might surprise users and I think if we changed:

Quoted 11 lines
cmd/gpt.c +11 -0
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				changed++;
+			}

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 687

Quoted 10 lines
cmd/gpt.c +10 -0
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				changed++;
+			}
+
+		}
+		if (changed == 0) {
+			printf("No matching partition names were found.\n");
+			return ret;
+		}

We could also test for if changed == 1 and return an error. I assume that a GPT with the same name used more than one time is already invalid, but we could be defensive here and test for != 2 instead. Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170611/fefff049/attachment.sig>
#37 lore raw

PATCH v7 1/1 GPT: provide commands to selectively rename partitions

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 258 insertions(+), 6 deletions(-)
cmd/Kconfig +8 -0
index 412bf24..7b262de 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +231 -5

296 lines not on this page · raw message

doc/README.gpt +19 -1
index 6c5ab78..d3db8bc 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
Signature · 1 line
2.1.4
#38 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

In reply to alison at peloton-tech.com

Dear Alison,

Quoted 4 lines · In message <[email protected]> you wrote:

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

Thanks.

One question: can multiple GPT partitions have the same name?

Quoted 3 lines

The 'swap' mode prints a warning if no matching partition names are found. If only one matching name of a provided pair is found, it renames the matching partitions to the new name.

I see a problem here...

Quoted 11 lines
cmd/gpt.c +11 -0
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				changed++;
+			}

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 687

Quoted 10 lines
cmd/gpt.c +10 -0
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				changed++;
+			}
+
+		}
+		if (changed == 0) {
+			printf("No matching partition names were found.\n");
+			return ret;
+		}

You will never know if there really was a pair of names that was swapped. Just a single rename of name1->name2 _or_ of name2->name1 will make the user think everything was fine.

[Note: I'm in the process of relocating and will be offline for the next 2..3. days. Don't expect more comments from mee soon. Sorry...]

Best regards,

Wolfgang Denk

Signature · 7 lines
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"I dislike companies that have a we-are-the-high-priests-of-hardware-
so-you'll-like-what-we-give-you attitude. I like commodity markets in
which iron-and-silicon hawkers know that they exist to  provide  fast
toys for software types like me to play with..."    - Eric S. Raymond
#39 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Quoted 5 lines · Wolfgang Denk

Dear Alison,

In message <[email protected]> you

Quoted 1 line · wrote:
Quoted 8 lines
Quoted 3 lines

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

Thanks.

One question: can multiple GPT partitions have the same name?

The idea behind the 'swap' mode is that a storage device can have two sets of partitions, one set all named 'primary' and one set all named 'backup'.
The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being interrupted.

Quoted 32 lines
Quoted 4 lines

The 'swap' mode prints a warning if no matching partition names are found. If only one matching name of a provided pair is found, it renames the matching partitions to the new name.

I see a problem here...

Review

Quoted 2 lines
(quoted diff) +2 -0
+     if (!strcmp(subcomm, "swap")) {
+             if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) >

PART_NAME_LEN)) {

Quoted 1 line

+ printf("Names longer than %d characters are

truncated.\n", PART_NAME_LEN);

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 5 lines
cmd/gpt.c +5 -0
+                     return -EINVAL;
+             }
+             list_for_each(pos, &disk_partitions) {
+                     curr = list_entry(pos, struct disk_part, list);
+                     if (!strcmp((char *)curr->gpt_part_info.name,

name1)) {

Quoted 1 line

+ strcpy((char *)curr->gpt_part_info.name,

name2);

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 3 lines
cmd/gpt.c +3 -0
+                             changed++;
+                     }
+                     else if (!strcmp((char *)curr->gpt_part_info.name,

name2)) {

Quoted 1 line

+ strcpy((char *)curr->gpt_part_info.name,

name1);

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 6 lines
cmd/gpt.c +6 -0
+                             changed++;
+                     }
+
+             }
+             if (changed == 0) {
+                     printf("No matching partition names were
Quoted 8 lines

found.\n");

Review

Quoted 2 lines
(quoted diff) +2 -0
+                     return ret;
+             }

You will never know if there really was a pair of names that was swapped. Just a single rename of name1->name2 _or_ of name2->name1 will make the user think everything was fine.

Point taken. The last version I posted has two counters instead of just
changed in order to address this problem.

Quoted 5 lines

[Note: I'm in the process of relocating and will be offline for the next 2..3. days. Don't expect more comments from mee soon. Sorry...]
Best regards,
Wolfgang Denk

One additional note: the last version I posted worked fine for the sandbox, but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone have
a better idea to solve this problem?

Thanks,
Alison Chaiken
Peloton Technology

#40 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Quoted 13 lines · Alison Chaiken
Quoted 11 lines · Wolfgang Denk

Dear Alison,

In message <[email protected]> you

Quoted 4 lines · wrote:

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

Thanks.

Quoted 8 lines
Quoted 1 line

One question: can multiple GPT partitions have the same name?

The idea behind the 'swap' mode is that a storage device can have two sets of partitions, one set all named 'primary' and one set all named 'backup'. The software updater in userspace can then simply rename
the partitions with sgdisk in order to pick the new image. The swap
mode changes the whole set of labels at once, so there's little chance of being interrupted.

I'm a little confused here now then. Can you provide an example set of usage, in the cover letter for v8 of the series (see below) that makes it a bit clearer? Thanks!

Quoted 53 lines
Quoted 31 lines
Quoted 3 lines

The 'swap' mode prints a warning if no matching partition names are found. If only one matching name of a provided pair is found, it renames the matching partitions to the new name.

I see a problem here...

Review

Quoted 2 lines
(quoted diff) +2 -0
+     if (!strcmp(subcomm, "swap")) {
+             if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) >

PART_NAME_LEN)) {

Quoted 1 line

+ printf("Names longer than %d characters are

truncated.\n", PART_NAME_LEN);

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 5 lines
cmd/gpt.c +5 -0
+                     return -EINVAL;
+             }
+             list_for_each(pos, &disk_partitions) {
+                     curr = list_entry(pos, struct disk_part, list);
+                     if (!strcmp((char *)curr->gpt_part_info.name,

name1)) {

Quoted 1 line

+ strcpy((char *)curr->gpt_part_info.name,

name2);

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 3 lines
cmd/gpt.c +3 -0
+                             changed++;
+                     }
+                     else if (!strcmp((char *)curr->gpt_part_info.name,

name2)) {

Quoted 1 line

+ strcpy((char *)curr->gpt_part_info.name,

name1);

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 6 lines
cmd/gpt.c +6 -0
+                             changed++;
+                     }
+
+             }
+             if (changed == 0) {
+                     printf("No matching partition names were
Quoted 8 lines

found.\n");

Review

Quoted 2 lines
(quoted diff) +2 -0
+                     return ret;
+             }

You will never know if there really was a pair of names that was swapped. Just a single rename of name1->name2 _or_ of name2->name1 will make the user think everything was fine.

Point taken. The last version I posted has two counters instead of just
changed in order to address this problem.

Quoted 5 lines

[Note: I'm in the process of relocating and will be offline for the next 2..3. days. Don't expect more comments from mee soon. Sorry...]
Best regards,
Wolfgang Denk

Quoted 6 lines

One additional note: the last version I posted worked fine for the sandbox, but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone have
a better idea to solve this problem?

Looking at the man page for atoi:
The atoi() function converts the initial portion of the string pointed to by nptr to int. The behavior is the same as

	strtol(nptr, NULL, 10);

So we should just re-work to use simple_strtol here. And since you brought it up on IRC, I suppose at this point a 'clean' posting of all 5 patches marked as 'v8' might make it easier to see what's what and in what order. Thanks again!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170612/a0d7e5bc/attachment.sig>
#41 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Dear Tom,

Quoted 11 lines · In message <20170612145646.GY10782@bill-the-cat> you wrote:

Looking at the man page for atoi:
The atoi() function converts the initial portion of the string pointed to by nptr to int. The behavior is the same as

	strtol(nptr, NULL, 10);

So we should just re-work to use simple_strtol here. And since you brought it up on IRC, I suppose at this point a 'clean' posting of all 5 patches marked as 'v8' might make it easier to see what's what and in what order. Thanks again!

Hm... the claim that the behaviour is the _same_ is not strictly correct.

atoi() returns "int", while strtol() returns "long int"...

Anyway, you are right that atoi() is not being used anywhere in active U-Boot code.

Best regards,

Wolfgang Denk

Signature · 4 lines
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
C++ is the best example of second-system effect since OS/360.
#42 lore raw

v7 cover add support for GPT partition name manipulation

From: Alison Chaiken <[email protected]>

Here is a resubmission of the 9-part patch series, the first 8 of which have already been marked 'applied', 'reviewed', or 'ack'ed' by Lukasz Majewski, Simon Glass or Tom Rini. I'm reposting them all as a set at Tom Rini's suggestion. Those earlier patches are listed here:

GPT: read partition table from device into a data structure

GPT: add accessor function for disk GUID

partitions: increase MAX_SEARCH_PARTITIONS and move to part.h

cmd gpt: test in sandbox
Applied to u-boot-dm by Simon Glass, Jun 15 in <CAPnjgZ0G6QADVFLC0mExQN3HXhLXbgE4neBEtmWAg0YZu-=aNg@mail.gmail.com>

sandbox: README: fix partition command invocation

GPT: fix error in partitions string doc
Ack'ed by Lukasz Majewski, May 31, in <0170531132155.33a558e7@jawa>

disk_partition: introduce macros for description string lengths

EFI: replace number with UUID_STR_LEN macro

Changes since last version to the last patch in the series:

-- Removed several casts in create_gpt_partitions_list() and
do_rename_gpt_parts() as suggested by Lothar Waßmann. The cast of gpt_part_info.name to char* is needed to silence a compiler warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
string it optionally prints is useful as input to the pre-existing 'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
by Tom Rini.

Changes to penultimate patch:
-- Removed a cast in allocate_disk_part() as suggested by Lothar.

Remaining tasks planned for future patches:

-- Create tests for GPT functionality as suggested by Lukasz.

-- Improve support for CONFIG_RANDOM_UUID.

-- Preserve partition type info when rewriting GPT.

Alison Chaiken (9):
EFI: replace number with UUID_STR_LEN macro
disk_partition: introduce macros for description string lengths
GPT: fix error in partitions string doc
sandbox: README: fix partition command invocation
cmd gpt: test in sandbox
partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
GPT: add accessor function for disk GUID
GPT: read partition table from device into a data structure
GPT: provide commands to selectively rename partitions

 board/sandbox/README.sandbox |   2 +-
 cmd/Kconfig                  |   8 +
 cmd/gpt.c                    | 376 ++++++++++++++++++++++++++++++++++++++++++-
 disk/part.c                  |   1 -
 disk/part_efi.c              |  33 +++-
 doc/README.gpt               |  39 ++++-
 include/part.h               |  35 +++-
 7 files changed, 481 insertions(+), 13 deletions(-)
Signature · 1 line
2.1.4
#43 lore raw

PATCH v7 1/9 EFI: replace number with UUID_STR_LEN macro

From: Alison Chaiken <[email protected]>

Changes since v6: none.

---
 disk/part_efi.c | 2 +-
 include/part.h  | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)
disk/part_efi.c +1 -1
index 1b7ba27..20d33ef 100644
@@ -183,7 +183,7 @@ void part_print_efi(struct blk_desc *dev_desc)
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
 	gpt_entry *gpt_pte = NULL;
 	int i = 0;
-	char uuid[37];
+	char uuid[UUID_STR_LEN + 1];
 	unsigned char *uuid_bin;
 
 	/* This function validates AND fills in the GPT header and PTE */
include/part.h +3 -2
index 83bce05..6ace09f 100644
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <uuid.h>
 
 struct block_drvr {
 	char *name;
@@ -54,10 +55,10 @@ typedef struct disk_partition {
 	uchar	type[32];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-	char	uuid[37];	/* filesystem UUID as string, if exists	*/
+	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
 #endif
 #ifdef CONFIG_PARTITION_TYPE_GUID
-	char	type_guid[37];	/* type GUID as string, if exists	*/
+	char	type_guid[UUID_STR_LEN + 1];	/* type GUID as string, if exists	*/
 #endif
 #ifdef CONFIG_DOS_PARTITION
 	uchar	sys_ind;	/* partition type 			*/
Signature · 1 line
2.1.4
#44 lore raw

PATCH v7 1/9 EFI: replace number with UUID_STR_LEN macro

Quoted 5 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/3ecb51ad/attachment.sig>
#45 lore raw

PATCH v7 2/9 disk_partition: introduce macros for description string lengths

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Changes since v6: none.

---
 include/part.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
include/part.h +5 -2
index 6ace09f..87b1111 100644
@@ -47,12 +47,15 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define PART_NAME_LEN 32
+#define PART_TYPE_LEN 32
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
 	lbaint_t	size;	/* number of blocks in partition	*/
 	ulong	blksz;		/* block size in bytes			*/
-	uchar	name[32];	/* partition name			*/
-	uchar	type[32];	/* string type description		*/
+	uchar	name[PART_NAME_LEN];	/* partition name			*/
+	uchar	type[PART_TYPE_LEN];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
Signature · 1 line
2.1.4
#46 lore raw

PATCH v7 2/9 disk_partition: introduce macros for description string lengths

Quoted 5 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/5cc1ee50/attachment.sig>
#47 lore raw

PATCH v7 3/9 GPT: fix error in partitions string doc

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt accordingly.

Changes since v6: none.

---
 doc/README.gpt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
doc/README.gpt +4 -4
index 3fcd835..589295b 100644
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -219,7 +219,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -241,7 +241,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
Signature · 1 line
2.1.4
#48 lore raw

PATCH v7 3/9 GPT: fix error in partitions string doc

Quoted 9 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt accordingly.

Quoted 3 lines

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/b77ecd23/attachment.sig>
#49 lore raw

PATCH v7 4/9 sandbox: README: fix partition command invocation

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

The instructions for creating a disk image that are presently in README.sandbox fail because sfdisk doesn't know about GPT.

Changes since v6: none.

---
 board/sandbox/README.sandbox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
board/sandbox/README.sandbox +1 -1
index 02d8ab3..9dc2eb0 100644
@@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image
 A disk image can be created using the following commands:
 
 $> truncate -s 1200M ./disk.raw
-$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk  ./disk.raw
+$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk  ./disk.raw
 $> lodev=`sudo losetup -P -f --show ./disk.raw`
 $> sudo mkfs.vfat -n EFI -v ${lodev}p1
 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
Signature · 1 line
2.1.4
#50 lore raw

PATCH v7 4/9 sandbox: README: fix partition command invocation

Quoted 8 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

The instructions for creating a disk image that are presently in README.sandbox fail because sfdisk doesn't know about GPT.

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/c10c2e25/attachment.sig>
#51 lore raw

PATCH v7 5/9 cmd gpt: test in sandbox

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make minor changes to README.gpt and sandbox_defconfig to support testing of the gpt command's functionality in the sandbox.

Changes since v6: none.

---
 doc/README.gpt | 10 ++++++++++
 1 file changed, 10 insertions(+)
doc/README.gpt +10 -0
index 589295b..0a3286f 100644
@@ -210,6 +210,16 @@ U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
 
+The GPT functionality may be tested with the 'sandbox' board by
+creating a disk image as described under 'Block Device Emulation' in
+board/sandbox/README.sandbox:
+
+=>host bind 0 ./disk.raw
+=> gpt read host 0
+[ . . . ]
+=> gpt flip host 0
+[ . . . ]
+
 Partition type GUID:
 ====================
 
Signature · 1 line
2.1.4
#52 lore raw

PATCH v7 5/9 cmd gpt: test in sandbox

Quoted 8 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

Make minor changes to README.gpt and sandbox_defconfig to support testing of the gpt command's functionality in the sandbox.

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/433e43e0/attachment.sig>
#53 lore raw

PATCH v7 6/9 partitions: increase MAX_SEARCH_PARTITIONS and move to part.h

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd directory can find it. At the same time, increase the value to 64 since some operating systems use many, and the resources consumed by a larger value are minimal.

Changes since v6: none.

---
 disk/part.c    | 1 -
 include/part.h | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)
disk/part.c +0 -1
index 491b02d..e640a55 100644
@@ -388,7 +388,6 @@ cleanup:
 
 #define PART_UNSPECIFIED -2
 #define PART_AUTO -1
-#define MAX_SEARCH_PARTITIONS 16
 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 			     struct blk_desc **dev_desc,
 			     disk_partition_t *info, int allow_whole_dev)
include/part.h +1 -0
index 87b1111..22da604 100644
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 64
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
Signature · 1 line
2.1.4
#54 lore raw

PATCH v7 6/9 partitions: increase MAX_SEARCH_PARTITIONS and move to part.h

Quoted 10 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd directory can find it. At the same time, increase the value to 64 since some operating systems use many, and the resources consumed by a larger value are minimal.

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/98a57a06/attachment.sig>
#55 lore raw

PATCH v7 7/9 GPT: add accessor function for disk GUID

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Changes since v6: none.

---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)
cmd/gpt.c +26 -0
index 3e98821..65fb80b 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +477,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +31 -0
index 20d33ef..71c3cb3 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -EINVAL;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = gpt_head->disk_guid.b;
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
doc/README.gpt +2 -1
index 0a3286f..6c5ab78 100644
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
include/part.h +15 -0
index 22da604..c41aa6a 100644
@@ -372,6 +372,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
Signature · 1 line
2.1.4
#56 lore raw

PATCH v7 7/9 GPT: add accessor function for disk GUID

Quoted 10 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Changes since v6: none.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/41b5b6db/attachment.sig>
#57 lore raw

PATCH v7 8/9 GPT: read partition table from device into a data structure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

Change since v6:
-- Removed a cast in allocate_disk_part() as suggested by Lothar.

---
 cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 126 insertions(+)
cmd/gpt.c +119 -0
index 65fb80b..9934ef4 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,118 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;
+ out:
+	if (valid_parts >= 2)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +570,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +594,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +7 -0
index c41aa6a..0cd803a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#58 lore raw

PATCH v7 8/9 GPT: read partition table from device into a data structure

Hi,

Quoted 112 lines · On Sun, 25 Jun 2017 16:43:24 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

Change since v6:
-- Removed a cast in allocate_disk_part() as suggested by Lothar.

---
 cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 126 insertions(+)
cmd/gpt.c +82 -0
index 65fb80b..9934ef4 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,118 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 245

Quoted 10 lines
cmd/gpt.c +9 -0
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
 

You initialize valid_parts to '1' and only ever increment it, so it can never be '0' here.

Lothar Waßmann

#59 lore raw

PATCH v8 8/10 GPT: read partition table from device into a data structure

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---

Changes since v7:
The failure-handling logic of get_gpt_info() now is triggered properly when valid_part=1.

 cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 126 insertions(+)
cmd/gpt.c +119 -0
index 65fb80b..dd5f78b 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,118 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (valid_parts == 1) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;
+ out:
+	if (valid_parts >= 2)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +570,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +594,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +7 -0
index c41aa6a..0cd803a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#60 lore raw

PATCH v8 8/10 GPT: read partition table from device into a data structure

Hi,

Quoted 21 lines · On Sat, 1 Jul 2017 15:42:57 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---

Changes since v7:
The failure-handling logic of get_gpt_info() now is triggered properly when valid_part=1.

 cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 126 insertions(+)
cmd/gpt.c +0 -0
index 65fb80b..dd5f78b 100644

[...]

Quoted 18 lines
cmd/gpt.c +17 -0
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 248

Quoted 10 lines
cmd/gpt.c +10 -0
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (valid_parts == 1) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;

I personally find it somewhat strange to initialize a counter to 1 and then return its value reduced by one, rather than initializing it to 0 and returning the exact counter value.

Lothar Waßmann

#61 lore raw

PATCH v8 8/10 GPT: read partition table from device into a data structure

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 128 insertions(+)
cmd/gpt.c +0 -0
index 65fb80b3df..8457b80757 100644

Changes since v7:
-- Made counter in get_gpt_info() start at 0 rather than 1. -- Checkpatch cleanup.

@@ -19,6 +19,9 @@
#include <linux/ctype.h>
#include <div64.h>
#include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);

/**
* extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,120 @@ static bool found_key(const char *str, const char *key)
return result;
}

+static void del_gpt_info(void)
+{
+ struct list_head *pos = &disk_partitions;
+ struct disk_part *curr;
+ while (!list_empty(pos)) {
+ curr = list_entry(pos->next, struct disk_part, list);
+ list_del(pos->next);
+ free(curr);
+ }
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum) +{
+ struct disk_part *newpart;
+ newpart = malloc(sizeof(*newpart));
+ if (!newpart)
+ return ERR_PTR(-ENOMEM);
+ memset(newpart, '\0', sizeof(newpart));
+
+ newpart->gpt_part_info.start = info->start;
+ newpart->gpt_part_info.size = info->size;
+ newpart->gpt_part_info.blksz = info->blksz;
+ strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+ PART_NAME_LEN);
+ newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+ strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+ PART_TYPE_LEN);
+ newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+ newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+ strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+ UUID_STR_LEN);
+ /* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+ newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+ newpart->partnum = partnum;
+
+ return newpart;
+}
+
+static void print_gpt_info(void)
+{
+ struct list_head *pos;
+ struct disk_part *curr;
+
+ list_for_each(pos, &disk_partitions) {
+ curr = list_entry(pos, struct disk_part, list);
+ printf("Partition %d:\n", curr->partnum);
+ printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+ (unsigned)curr->gpt_part_info.size);
+ printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+ curr->gpt_part_info.name);
+ printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+ curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+ printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+ printf("\n");
+ }
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+ /* start partition numbering at 1, as U-Boot does */
+ int valid_parts = 0, p, ret;
+ disk_partition_t info;
+ struct disk_part *new_disk_part;
+
+ if (disk_partitions.next == NULL)
+ INIT_LIST_HEAD(&disk_partitions);
+
+ for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+ ret = part_get_info(dev_desc, p, &info);
+ if (ret)
+ continue;
+
+ /* Add 1 here because counter is zero-based but p1 is
+ the first partition */
+ new_disk_part = allocate_disk_part(&info, valid_parts+1);
+ if (IS_ERR(new_disk_part))
+ goto out;
+
+ list_add_tail(&new_disk_part->list, &disk_partitions);
+ valid_parts++;
+ }
+ if (valid_parts == 0) {
+ printf("** No valid partitions found **\n");
+ goto out;
+ }
+ return valid_parts;
+ out:
+ if (valid_parts >= 1)
+ del_gpt_info();
+ return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+ int ret;
+
+ ret = get_gpt_info(dev_desc);
+ if (ret > 0) {
+ print_gpt_info();
+ del_gpt_info();
+ return 0;
+ }
+ return ret;
+}
+
/**
* set_gpt_info(): Fill partition information from string
* function allocates memory, remember to free!
@@ -455,6 +572,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf("Verify GPT: ");
} else if (strcmp(argv[1], "guid") == 0) {
ret = do_disk_guid(blk_dev_desc, argv[4]);
+ } else if (strcmp(argv[1], "read") == 0) {
+ ret = do_get_gpt_info(blk_dev_desc);
} else {
return CMD_RET_USAGE;
}
@@ -477,6 +596,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
" Example usage:\n"
" gpt write mmc 0 $partitions\n"
" gpt verify mmc 0 $partitions\n"
+ " read <interface> <dev>\n"
+ " - read GPT into a data structure for manipulation\n"
" guid <interface> <dev>\n"
" - print disk GUID\n"
" guid <interface> <dev> <varname>\n"

include/part.h +7 -0
index c41aa6adc2..0cd803a933 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.13.2
#62 lore raw

PATCH v8 8/10 GPT: read partition table from device into a data structure

Quoted 7 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

After changing this to only be adding significant code when CMD_GPT_RENAME is enabled, applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/43f8eb20/attachment.sig>
#63 lore raw

PATCH v7 9/9 GPT: provide commands to selectively rename partitions

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Changes since v7:

-- Removed several casts in create_gpt_partitions_list() and
do_rename_gpt_parts() as suggested by Lothar Waßmann. The cast of gpt_part_info.name to char* is needed to silence a compiler warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
string it optionally prints is useful as input to the pre-existing 'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
by Tom Rini.

---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)
cmd/Kconfig +8 -0
index 07b0e3b..ae61b96 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +234 -5

299 lines not on this page · raw message

doc/README.gpt +19 -1
index 6c5ab78..d3db8bc 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
Signature · 1 line
2.1.4
#64 lore raw

PATCH v7 9/9 GPT: provide commands to selectively rename partitions

Hi

Quoted 29 lines · On Mon, Jun 26, 2017 at 7:43 AM, <[email protected]> wrote:

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Changes since v7:

-- Removed several casts in create_gpt_partitions_list() and
do_rename_gpt_parts() as suggested by Lothar Waßmann. The cast of gpt_part_info.name to char* is needed to silence a compiler warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
number of partitions with which to continue.

Quoted 7 lines

-- Added a comment to do_rename_gpt_parts() noting that the debug()
string it optionally prints is useful as input to the pre-existing 'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
by Tom Rini.

Can you please remove the changelog from the commit message, instead put it in the commit-notes section below ---?

Quoted 8 lines
---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)

[snip]

Regards,
Bin

#65 lore raw

PATCH v7 9/9 GPT: provide commands to selectively rename partitions

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)

Changes since v7:

-- Removed several casts in create_gpt_partitions_list() and
do_rename_gpt_parts() as suggested by Lothar Waßmann. The cast of gpt_part_info.name to char* is needed to silence a compiler warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
string it optionally prints is useful as input to the pre-existing 'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
by Tom Rini.

cmd/Kconfig +8 -0
index 07b0e3b..ae61b96 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +234 -5

299 lines not on this page · raw message

doc/README.gpt +19 -1
index 6c5ab78..d3db8bc 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
Signature · 1 line
2.1.4
#66 lore raw

PATCH v7 9/9 GPT: provide commands to selectively rename partitions

In reply to alison at peloton-tech.com

Hi,

Quoted 162 lines · On Sun, 25 Jun 2017 16:43:25 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Changes since v7:

-- Removed several casts in create_gpt_partitions_list() and
do_rename_gpt_parts() as suggested by Lothar Waßmann. The cast of gpt_part_info.name to char* is needed to silence a compiler warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
string it optionally prints is useful as input to the pre-existing 'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
by Tom Rini.

---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)
cmd/Kconfig +8 -0
index 07b0e3b..ae61b96 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +67 -2
index 9934ef4..8c0441f 100644
@@ -20,6 +20,8 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+#include <stdlib.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +196,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +234,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* see part.h for definition of struct disk_partition */
+	partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1);
+	partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -EINVAL;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);

cmd/gpt.c static void print_gpt_info(void) · line 292

Quoted 10 lines
cmd/gpt.c +9 -0
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
 

AFAICT lbaint_t is declared in include/blk.h and may be uint64_t or ulong depending on CONFIG_SYS_64BIT_LBA.

Quoted 62 lines
cmd/gpt.c +13 -0
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where

* it can be printed or modified

cmd/gpt.c +26 -2
@@ -226,8 +313,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -301,6 +391,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -530,6 +622,127 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
+
+	if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
+	    (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 653

Quoted 10 lines
cmd/gpt.c +9 -0
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts: -ENODEV;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
 

unnecessary type cast. A function that takes a 'const' argument may well be passed a non-'const' value.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 12 lines
cmd/gpt.c +11 -0
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	/*
+	 * Uncomment the following line to print a string that 'gpt write'
+	 * or 'gpt verify' will accept as input.
+	 */
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
 

dto.

[...]

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)

Quoted 12 lines
cmd/gpt.c +11 -0
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
 

dto.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 719

Quoted 6 lines
cmd/gpt.c +6 -0
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,

dto.

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 764

Quoted 7 lines
cmd/gpt.c +1 -1
@@ -547,7 +760,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
-	if (argc < 4 || argc > 5)
+	if (argc < 4 || argc > 6)
 

Other subcommands still accept only 4 parameters, so this check should possibly be done after checking the subcommand name, or at least made conditional on CONFIG_CMD_GPT_RENAME which enables the new subcommands.

Quoted 61 lines
cmd/gpt.c +0 -0
 		return CMD_RET_USAGE;
 
cmd/gpt.c +16 -0
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -572,6 +785,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} else if ((strcmp(argv[1], "swap") == 0) ||
+		   (strcmp(argv[1], "rename") == 0)) {
+		ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -603,4 +821,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\n"
+	"gpt rename <interface> <dev> <part> <name>\n"
+	"    - rename the specified partition\n"
+	" Example usage:\n"
+	" gpt swap mmc 0 foo bar\n"
+	" gpt rename mmc 0 3 foo\n"
+#endif
 );
doc/README.gpt +18 -0
index 6c5ab78..d3db8bc 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in

doc/README.gpt board/sandbox/README.sandbox: · line 242

Quoted 8 lines
doc/README.gpt +1 -1
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:

Lothar Waßmann

#67 lore raw

PATCH 9/10 GPT: provide commands to selectively rename partitions

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---

Changes since v7:
This version removes casts to unsigned long where the underlying data type is lbaint_t. I tested this version both with and without CONFIG_SYS_64BIT_LBA, and the output is fine in either case. This version also removes unneeded casts to const and restores the gpt command's error reporting to its earlier state if CONFIG_GPT_RENAME is unset.

In addition, there is an additional check that a malloc() has succeeded.

 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 doc/README.gpt |  20 ++++-
 3 files changed, 263 insertions(+), 5 deletions(-)
cmd/Kconfig +8 -0
index 07b0e3b..ae61b96 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +236 -4

301 lines not on this page · raw message

doc/README.gpt +19 -1
index 6c5ab78..d3db8bc 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
Signature · 1 line
2.1.4
#68 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

In reply to Alison Chaiken

Dear Alison,

Quoted 6 lines · In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.gmail.com>…

The idea behind the 'swap' mode is that a storage device can have two sets of partitions, one set all named 'primary' and one set all named 'backup'.
The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being interrupted.

It's still a sequential, non-atomic operation, and "little chance" is exactly the places where Murphy likes to hit you.

Quoted 6 lines

One additional note: the last version I posted worked fine for the sandbox, but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone have
a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library code from the tool chain.

Best regards,

Wolfgang Denk

Signature · 6 lines
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Looks clean and obviously correct to me, but then _everything_ I
write always looks obviously correct to me.  - Linus Torvalds in
<[email protected]>
#69 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Quoted 24 lines · Wolfgang Denk

Dear Alison,

In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.

Quoted 2 lines · gmail.com> you wrote:

The idea behind the 'swap' mode is that a storage device can have two

sets

Quoted 1 line

of partitions, one set all named 'primary' and one set all named

'backup'.

Quoted 3 lines

The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being

interrupted.

It's still a sequential, non-atomic operation, and "little chance" is exactly the places where Murphy likes to hit you.

Quoted 1 line

One additional note: the last version I posted worked fine for the

sandbox,

Quoted 4 lines

but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone

have

Quoted 9 lines
Quoted 1 line

a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library code from the tool chain.

Best regards,

Wolfgang Denk

I'm about to submit a new version of the patches that adopts Wolfgang's and Tom's suggestions about replacing atoi().

Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first modifies the names in an in-memory
data structure, and then uses the existing 'gpt write' functionality to change the actual partition table stored on the device. Thus, interruption of the new command is low-risk, as interruption of the modification of the new data structure has no persistent effect, and the risk associated with 'gpt write' is the same as always.

By the way, in the course of testing an earlier version of this patch series, I noticed that 'gpt write' and 'gpt verify' segv if presented with a non-null-terminated partitions string. It's the strlen function in lib that actually generates an error. I haven't yet quite figured out what the best solution to the problem is: should strlen() itself be modified, or is
it enough to test in gpt.c? The right solution is not to present the
commands with poorly formed strings, but it's easy to do so.

Mit freundlichen Grüße,
Alison

#70 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Quoted 47 lines · Alison Chaiken
Quoted 24 lines · Wolfgang Denk

Dear Alison,

In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.

Quoted 2 lines · gmail.com> you wrote:

The idea behind the 'swap' mode is that a storage device can have two

sets

Quoted 1 line

of partitions, one set all named 'primary' and one set all named

'backup'.

Quoted 3 lines

The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being

interrupted.

It's still a sequential, non-atomic operation, and "little chance" is exactly the places where Murphy likes to hit you.

Quoted 1 line

One additional note: the last version I posted worked fine for the

sandbox,

Quoted 4 lines

but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone

have

Quoted 9 lines
Quoted 1 line

a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library code from the tool chain.

Best regards,

Wolfgang Denk

I'm about to submit a new version of the patches that adopts Wolfgang's and Tom's suggestions about replacing atoi().

Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first modifies the names in an in-memory
data structure, and then uses the existing 'gpt write' functionality to change the actual partition table stored on the device. Thus, interruption of the new command is low-risk, as interruption of the modification of the new data structure has no persistent effect, and the risk associated with 'gpt write' is the same as always.

Quoted 7 lines

By the way, in the course of testing an earlier version of this patch series, I noticed that 'gpt write' and 'gpt verify' segv if presented with a non-null-terminated partitions string. It's the strlen function in lib that actually generates an error. I haven't yet quite figured out what the best solution to the problem is: should strlen() itself be modified, or is
it enough to test in gpt.c? The right solution is not to present the
commands with poorly formed strings, but it's easy to do so.

It is likely this particular bug is one of many in the class of using strlen when we cannot really be certain of well formatted input / buffer, sadly. So a fix to gpt.c and if you're so inclined, a git grep around for other likely cases.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170626/e271ce2a/attachment.sig>
#71 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

In reply to Alison Chaiken

Hi,

Quoted 47 lines · On Sun, 25 Jun 2017 14:54:56 -0700 Alison Chaiken wrote:
Quoted 24 lines · Wolfgang Denk

Dear Alison,

In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.

Quoted 2 lines · gmail.com> you wrote:

The idea behind the 'swap' mode is that a storage device can have two

sets

Quoted 1 line

of partitions, one set all named 'primary' and one set all named

'backup'.

Quoted 3 lines

The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being

interrupted.

It's still a sequential, non-atomic operation, and "little chance" is exactly the places where Murphy likes to hit you.

Quoted 1 line

One additional note: the last version I posted worked fine for the

sandbox,

Quoted 4 lines

but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone

have

Quoted 9 lines
Quoted 1 line

a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library code from the tool chain.

Best regards,

Wolfgang Denk

I'm about to submit a new version of the patches that adopts Wolfgang's and Tom's suggestions about replacing atoi().

Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first modifies the names in an in-memory
data structure, and then uses the existing 'gpt write' functionality to change the actual partition table stored on the device. Thus, interruption of the new command is low-risk, as interruption of the modification of the new data structure has no persistent effect, and the risk associated with 'gpt write' is the same as always.

Quoted 8 lines

By the way, in the course of testing an earlier version of this patch series, I noticed that 'gpt write' and 'gpt verify' segv if presented with a non-null-terminated partitions string. It's the strlen function in lib that actually generates an error. I haven't yet quite figured out what the best solution to the problem is: should strlen() itself be modified, or is
it enough to test in gpt.c? The right solution is not to present the
commands with poorly formed strings, but it's easy to do so.

You can use strnlen() if you know the maximum allowed length of the string.

NB: A quick glance at set_gpt_info() revealed this potential crash cause:

|	str = strdup(str_part);
|
|	/* extract disk guid */
|	s = str;
|	val = extract_val(str, "uuid_disk");

strdup() may fail (especially if the input string is not zero terminated) and return a NULL pointer which then will happily be used by extract_val().

Lothar Waßmann

#72 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Hi,

Quoted 63 lines · On Tue, 27 Jun 2017 09:05:14 +0200 Lothar Waßmann wrote:

Hi,

Quoted 47 lines · On Sun, 25 Jun 2017 14:54:56 -0700 Alison Chaiken wrote:
Quoted 24 lines · Wolfgang Denk

Dear Alison,

In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.

Quoted 2 lines · gmail.com> you wrote:

The idea behind the 'swap' mode is that a storage device can have two

sets

Quoted 1 line

of partitions, one set all named 'primary' and one set all named

'backup'.

Quoted 3 lines

The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being

interrupted.

It's still a sequential, non-atomic operation, and "little chance" is exactly the places where Murphy likes to hit you.

Quoted 1 line

One additional note: the last version I posted worked fine for the

sandbox,

Quoted 4 lines

but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone

have

Quoted 9 lines
Quoted 1 line

a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library code from the tool chain.

Best regards,

Wolfgang Denk

I'm about to submit a new version of the patches that adopts Wolfgang's and Tom's suggestions about replacing atoi().

Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first modifies the names in an in-memory
data structure, and then uses the existing 'gpt write' functionality to change the actual partition table stored on the device. Thus, interruption of the new command is low-risk, as interruption of the modification of the new data structure has no persistent effect, and the risk associated with 'gpt write' is the same as always.

Quoted 8 lines

By the way, in the course of testing an earlier version of this patch series, I noticed that 'gpt write' and 'gpt verify' segv if presented with a non-null-terminated partitions string. It's the strlen function in lib that actually generates an error. I haven't yet quite figured out what the best solution to the problem is: should strlen() itself be modified, or is
it enough to test in gpt.c? The right solution is not to present the
commands with poorly formed strings, but it's easy to do so.

You can use strnlen() if you know the maximum allowed length of the string.

NB: A quick glance at set_gpt_info() revealed this potential crash cause:

Quoted 9 lines
|	str = strdup(str_part);
|
|	/* extract disk guid */
|	s = str;
|	val = extract_val(str, "uuid_disk");

strdup() may fail (especially if the input string is not zero terminated) and return a NULL pointer which then will happily be used by extract_val().

There are some more highlights in this code:
| *str_disk_guid = malloc(UUID_STR_LEN + 1);
| gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);

Quoted 1 line

malloc() can fail too.

|		*str_disk_guid = strdup(p);
|		free(val);
|		/* Move s to first partition */
|		strsep(&s, ";");
Quoted 1 line

if strdup() fails, *str_disk_guid will be a NULL pointer, but the function will return success eventually and the NULL pointer will be passed on to subsequent functions without further checks.

|static bool found_key(const char *str, const char *key)
|{
|	char *k;
|	char *s, *strcopy;
|	bool result = false;
|
|	strcopy = strdup(str);
|	if (!strcopy)
|		return NULL;
Quoted 1 line

The function has a bool return type, but returns a pointer type here. This accidentally works as expected.

Lothar Waßmann

#73 lore raw

PATCH 10/10 gpt: harden set_gpt_info() against non NULL-terminated strings

From: Alison Chaiken <[email protected]>

Strings read from devices may sometimes fail to be
NULL-terminated. The functions in lib/string.c are subject to
failure in this case. Protect against observed failures in
set_gpt_info() by switching to length-checking variants with a length limit of the maximum possible partition table length. At the same time, add a few checks for NULL string pointers.

Here is an example as observed in sandbox under GDB:

    => gpt verify host 0 $partitions
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    267             for (sc = s; *sc != '\0'; ++sc)
    (gdb) bt
    #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
    str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
    parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
    #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
    #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
    at cmd/gpt.c:783
    #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
    cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
    #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
    repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539
---
 cmd/gpt.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)
cmd/gpt.c +19 -9
index 73bf273..8bd7bdf 100644
@@ -233,7 +233,7 @@ static void print_gpt_info(void)
 	}
 }
 
-#ifdef CONFIG_CMD_GPT_RENAME
+
 static int calc_parts_list_len(int numparts)
 {
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
@@ -253,6 +253,7 @@ static int calc_parts_list_len(int numparts)
 	return partlistlen;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
 /*
  * create the string that upstream 'gpt write' command will accept as an
  * argument
@@ -381,6 +382,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	int errno = 0;
 	uint64_t size_ll, start_ll;
 	lbaint_t offset = 0;
+        int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
 
 	debug("%s:  lba num: 0x%x %d\n", __func__,
 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
@@ -398,6 +400,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
+		if (str_disk_guid == NULL)
+			return -ENOMEM;
 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
 #else
 		free(str);
@@ -412,10 +416,14 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		/* Move s to first partition */
 		strsep(&s, ";");
 	}
-	if (strlen(s) == 0)
+	if (s == NULL) {
+                printf("Error: is the partitions string NULL-terminated?\n");
+		return -EINVAL;
+	}
+	if (strnlen(s, max_str_part) == 0)
 		return -3;
 
-	i = strlen(s) - 1;
+	i = strnlen(s, max_str_part) - 1;
 	if (s[i] == ';')
 		s[i] = '\0';
 
@@ -429,6 +437,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 
 	/* allocate memory for partitions */
 	parts = calloc(sizeof(disk_partition_t), p_count);
+	if (parts == NULL)
+		return -ENOMEM;
 
 	/* retrieve partitions data from string */
 	for (i = 0; i < p_count; i++) {
@@ -450,12 +460,12 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		} else {
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].uuid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
 				printf("Wrong uuid format for partition %d\n", i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].uuid, p);
+			strncpy((char *)parts[i].uuid, p, max_str_part);
 			free(val);
 		}
 #ifdef CONFIG_PARTITION_TYPE_GUID
@@ -465,13 +475,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 			/* 'type' is optional */
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].type_guid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
 				printf("Wrong type guid format for partition %d\n",
 				       i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].type_guid, p);
+			strncpy((char *)parts[i].type_guid, p, max_str_part);
 			free(val);
 		}
 #endif
@@ -483,11 +493,11 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		}
 		if (extract_env(val, &p))
 			p = val;
-		if (strlen(p) >= sizeof(parts[i].name)) {
+		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
 			errno = -4;
 			goto err;
 		}
-		strcpy((char *)parts[i].name, p);
+		strncpy((char *)parts[i].name, p, max_str_part);
 		free(val);
 
 		/* size */
Signature · 1 line
2.1.4
#74 lore raw

PATCH 10/10 gpt: harden set_gpt_info() against non NULL-terminated strings

Hi,

Quoted 56 lines · On Sat, 1 Jul 2017 15:44:44 -0700 alison at peloton-tech.com wrote:

From: Alison Chaiken <[email protected]>

Strings read from devices may sometimes fail to be
NULL-terminated. The functions in lib/string.c are subject to
failure in this case. Protect against observed failures in
set_gpt_info() by switching to length-checking variants with a length limit of the maximum possible partition table length. At the same time, add a few checks for NULL string pointers.

Here is an example as observed in sandbox under GDB:

    => gpt verify host 0 $partitions
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    267             for (sc = s; *sc != '\0'; ++sc)
    (gdb) bt
    #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
    str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
    parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
    #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
    #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
    at cmd/gpt.c:783
    #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
    cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
    #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
    repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539
---
 cmd/gpt.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)
cmd/gpt.c +2 -1
index 73bf273..8bd7bdf 100644
@@ -233,7 +233,7 @@ static void print_gpt_info(void)
 	}
 }
 
-#ifdef CONFIG_CMD_GPT_RENAME
+
 static int calc_parts_list_len(int numparts)
 {
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
@@ -253,6 +253,7 @@ static int calc_parts_list_len(int numparts)
 	return partlistlen;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
 /*
  * create the string that upstream 'gpt write' command will accept as an
  * argument

cmd/gpt.c static int set_gpt_info(struct blk_desc *dev_desc, · line 386

Quoted 5 lines
cmd/gpt.c +1 -0
@@ -381,6 +382,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	int errno = 0;
 	uint64_t size_ll, start_ll;
 	lbaint_t offset = 0;
+        int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
 

indentation should use tabs not spaces (scripts/checkpatch.pl would tell you).

Quoted 12 lines
cmd/gpt.c +2 -0
 	debug("%s:  lba num: 0x%x %d\n", __func__,
 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
@@ -398,6 +400,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
+		if (str_disk_guid == NULL)
+			return -ENOMEM;
 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
 #else
 		free(str);

cmd/gpt.c static int set_gpt_info(struct blk_desc *dev_desc, · line 422

Quoted 8 lines
cmd/gpt.c +3 -1
@@ -412,10 +416,14 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		/* Move s to first partition */
 		strsep(&s, ";");
 	}
-	if (strlen(s) == 0)
+	if (s == NULL) {
+                printf("Error: is the partitions string NULL-terminated?\n");
+		return -EINVAL;
 

dto.

Lothar Waßmann

#75 lore raw

PATCH v2 10/10 gpt: harden set_gpt_info() against non NULL-terminated strings

From: Alison Chaiken <[email protected]>

Strings read from devices may sometimes fail to be
NULL-terminated. The functions in lib/string.c are subject to
failure in this case. Protect against observed failures in
set_gpt_info() by switching to length-checking variants with a length limit of the maximum possible partition table length. At the same time, add a few checks for NULL string pointers.

Here is an example as observed in sandbox under GDB:

    => gpt verify host 0 $partitions
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    267             for (sc = s; *sc != '\0'; ++sc)
    (gdb) bt
    #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
    str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
    parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
    #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
    #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
    at cmd/gpt.c:783
    #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
    cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
    #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
    repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539

---

Changes since v1:
-- Checkpatch cleanups.

 cmd/gpt.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)
cmd/gpt.c +19 -9
index d703385a24..f8f35c23e0 100644
@@ -233,7 +233,7 @@ static void print_gpt_info(void)
 	}
 }
 
-#ifdef CONFIG_CMD_GPT_RENAME
+
 static int calc_parts_list_len(int numparts)
 {
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
@@ -253,6 +253,7 @@ static int calc_parts_list_len(int numparts)
 	return partlistlen;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
 /*
  * create the string that upstream 'gpt write' command will accept as an
  * argument
@@ -385,6 +386,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	int errno = 0;
 	uint64_t size_ll, start_ll;
 	lbaint_t offset = 0;
+	int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
 
 	debug("%s:  lba num: 0x%x %d\n", __func__,
 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
@@ -402,6 +404,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
+		if (str_disk_guid == NULL)
+			return -ENOMEM;
 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
 #else
 		free(str);
@@ -416,10 +420,14 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		/* Move s to first partition */
 		strsep(&s, ";");
 	}
-	if (strlen(s) == 0)
+	if (s == NULL) {
+		printf("Error: is the partitions string NULL-terminated?\n");
+		return -EINVAL;
+	}
+	if (strnlen(s, max_str_part) == 0)
 		return -3;
 
-	i = strlen(s) - 1;
+	i = strnlen(s, max_str_part) - 1;
 	if (s[i] == ';')
 		s[i] = '\0';
 
@@ -433,6 +441,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 
 	/* allocate memory for partitions */
 	parts = calloc(sizeof(disk_partition_t), p_count);
+	if (parts == NULL)
+		return -ENOMEM;
 
 	/* retrieve partitions data from string */
 	for (i = 0; i < p_count; i++) {
@@ -454,12 +464,12 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		} else {
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].uuid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
 				printf("Wrong uuid format for partition %d\n", i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].uuid, p);
+			strncpy((char *)parts[i].uuid, p, max_str_part);
 			free(val);
 		}
 #ifdef CONFIG_PARTITION_TYPE_GUID
@@ -469,13 +479,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 			/* 'type' is optional */
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].type_guid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
 				printf("Wrong type guid format for partition %d\n",
 				       i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].type_guid, p);
+			strncpy((char *)parts[i].type_guid, p, max_str_part);
 			free(val);
 		}
 #endif
@@ -487,11 +497,11 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		}
 		if (extract_env(val, &p))
 			p = val;
-		if (strlen(p) >= sizeof(parts[i].name)) {
+		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
 			errno = -4;
 			goto err;
 		}
-		strcpy((char *)parts[i].name, p);
+		strncpy((char *)parts[i].name, p, max_str_part);
 		free(val);
 
 		/* size */
Signature · 1 line
2.13.2
#76 lore raw

PATCH v2 10/10 gpt: harden set_gpt_info() against non NULL-terminated strings

Quoted 28 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

Strings read from devices may sometimes fail to be
NULL-terminated. The functions in lib/string.c are subject to
failure in this case. Protect against observed failures in
set_gpt_info() by switching to length-checking variants with a length limit of the maximum possible partition table length. At the same time, add a few checks for NULL string pointers.

Here is an example as observed in sandbox under GDB:

    => gpt verify host 0 $partitions
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    267             for (sc = s; *sc != '\0'; ++sc)
    (gdb) bt
    #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
    str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
    parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
    #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
    #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
    at cmd/gpt.c:783
    #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
    cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
    #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
    repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539
Quoted 2 lines

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/b9d0644c/attachment.sig>
#77 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

In reply to Lothar Waßmann
Quoted 59 lines · Lothar Waßmann

Hi,

Quoted 47 lines · On Sun, 25 Jun 2017 14:54:56 -0700 Alison Chaiken wrote:
Quoted 24 lines · Wolfgang Denk

Dear Alison,

In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.

Quoted 2 lines · gmail.com> you wrote:

The idea behind the 'swap' mode is that a storage device can have two

sets

Quoted 1 line

of partitions, one set all named 'primary' and one set all named

'backup'.

Quoted 3 lines

The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image. The swap mode changes the
whole set of labels at once, so there's little chance of being

interrupted.

It's still a sequential, non-atomic operation, and "little chance" is exactly the places where Murphy likes to hit you.

Quoted 1 line

One additional note: the last version I posted worked fine for the

sandbox,

Quoted 4 lines

but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi(). I guess the libc for the x86 compiler
includes it. To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution. Does anyone

have

Quoted 9 lines
Quoted 1 line

a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library code from the tool chain.

Best regards,

Wolfgang Denk

I'm about to submit a new version of the patches that adopts Wolfgang's and Tom's suggestions about replacing atoi().

Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first modifies the names in an in-memory
data structure, and then uses the existing 'gpt write' functionality to change the actual partition table stored on the device. Thus, interruption of the new command is low-risk, as interruption of the modification of the new data structure has no persistent effect, and the risk associated with 'gpt write' is the same as always.

Quoted 8 lines

By the way, in the course of testing an earlier version of this patch series, I noticed that 'gpt write' and 'gpt verify' segv if presented with a non-null-terminated partitions string. It's the strlen function in lib that actually generates an error. I haven't yet quite figured out what the best solution to the problem is: should strlen() itself be modified, or is
it enough to test in gpt.c? The right solution is not to present the
commands with poorly formed strings, but it's easy to do so.

Quoted 2 lines

You can use strnlen() if you know the maximum allowed length of the string.

Thanks for that tip: I didn't know that strnlen() existed. That
indeed seems like a good protection against at least the problems identified here.

Quoted 8 lines

NB: A quick glance at set_gpt_info() revealed this potential crash cause:

|       str = strdup(str_part);
|
|       /* extract disk guid */
|       s = str;
|       val = extract_val(str, "uuid_disk");
Quoted 7 lines

strdup() may fail (especially if the input string is not zero terminated) and return a NULL pointer which then will happily be used by extract_val().

Lothar Waßmann

The underlying cause of the problem is that u-boot's implementations
of strlen() and the CLI handle strings differently. The former
terminates strings only on NULLs, while the latter terminates strings
*either* on NULLs or on semicolons. Reading the partition table
back from a device's GPT results in a string with a NULL only at the
very end, but with one semicolon per partition. Running 'gpt verify
mmc 0 $partitions" or 'gpt write mmc 0 $partitions' therefore causes a crash if the user has previously typed 'setenv partitions 1;2;3;4;5;'
rather than 'setenv partitions "1;2;3;4;5;"'. In the former case,
the partitions string ends up being '1' without NULL-termination, resulting in the crash.

U-boot environment parameters often have lots of semi-colon-separated
lists. I'm not sure what other code paths lead to strlen() or
strdup(), as Lothar alludes to above, but it seems likely to me that
there are other ways to reproduce this bug. Looking at lib/string.c,
there are other functions like strcpy() that also check "!= '\0'".

--- Alison

#78 lore raw

PATCH v6 3/3 GPT: provide commands to selectively rename partitions

Hi,

Quoted 3 lines

The underlying cause of the problem is that u-boot's implementations
of strlen() and the CLI handle strings differently. The former

"u-boot's implementation" is conformant with the standard and well documented libc implementation that exists since the dawn of C programming.

Quoted 9 lines

terminates strings only on NULLs, while the latter terminates strings
*either* on NULLs or on semicolons. Reading the partition table
back from a device's GPT results in a string with a NULL only at the
very end, but with one semicolon per partition. Running 'gpt verify
mmc 0 $partitions" or 'gpt write mmc 0 $partitions' therefore causes a crash if the user has previously typed 'setenv partitions 1;2;3;4;5;'
rather than 'setenv partitions "1;2;3;4;5;"'. In the former case,
the partitions string ends up being '1' without NULL-termination,

That's nonsense. _Every_ string in the environment is NULL terminated. In the former case of your example the characters after the first semicolon are interpreted as commands and lead to an error message Unknown command '2' - try 'help'
...
because the ';' is treated as a command terminator by the parser unless quoted.

Lothar Waßmann

#79 lore raw

PATCH v8 9/10 GPT: provide commands to selectively rename partitions

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---

Changes since v7:
-- Checkpatch cleanups.

 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 doc/README.gpt |  20 ++++-
 3 files changed, 264 insertions(+), 5 deletions(-)
cmd/Kconfig +8 -0
index 6758db16f3..8d6fcb576d 100644
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +237 -4

302 lines not on this page · raw message

doc/README.gpt +19 -1
index 6c5ab7858a..d3db8bce1c 100644
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
Signature · 1 line
2.13.2
#80 lore raw

PATCH v8 9/10 GPT: provide commands to selectively rename partitions

Quoted 11 lines · Alison Chaiken

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via new 'gpt swap' and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names are found, or if the number of partitions with one name does not equal
the number with the second name. The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Quoted 6 lines

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/e678c149/attachment.sig>
#81 lore raw

PATCH v3 5/5 GPT: fix error in partitions string doc

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt and file comments accordingly.

---
 cmd/gpt.c      | 13 +------------
 doc/README.gpt |  8 ++++----
 2 files changed, 5 insertions(+), 16 deletions(-)
cmd/gpt.c +1 -12
index f6968de..e2cb2a1 100644
@@ -232,12 +232,6 @@ static void print_gpt_info(void)
 #ifdef CONFIG_CMD_GPT_FLIP
 static int calc_parts_list_len(int numparts)
 {
-	/*
-	 * prefatory string:
-	 * doc/README.GPT, suggests that
-	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
-	 * is correct, but extract_val() expects "uuid_disk" first.
-	 */
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
 	/* for the comma */
 	partlistlen++;
@@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
  * argument
  *
  * From doc/README.gpt, Format of partitions layout:
- *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
  *	name=kernel,size=60MiB,uuid=...;"
  * The fields 'name' and 'size' are mandatory for every partition.
  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
@@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int numparts, const char *guid, char *part
 	if (!partitions_list)
 		return -1;
 
-	/*
-	 * README.gpt specifies starting with "partitions=" like so:
-	 *      strcpy(partitions_list, "partitions=uuid_disk=");
-	 * but that breaks extract_val, which doesn't skip over 'partitions='.
-	 */
 	strcpy(partitions_list, "uuid_disk=");
 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
 	strcat(partitions_list, ";");
doc/README.gpt +4 -4
index e29b188..754e490 100644
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -255,7 +255,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
Signature · 1 line
2.1.4
#82 lore raw

v3 cover add support for GPT partition name manipulation

In reply to alison at peloton-tech.com
Quoted 11 lines · On Fri, 2 Jun 2017 19:22:29 -0700 alison at peloton-tech.com wrote:

Significant changes since v2:
-- Got rid of the need to allocate memory for the GUID string in
do_gpt();
-- Fixed the problems with string NULL termination in
allocate_disk_part();
-- Removed duplicate definition of MAX_SEARCH_PARTITIONS from
disk/part.c and increased the value in include/part.h to 64;
-- Improved the commit message for "rename GPT partitions to detect
boot failure" to better describe the version of the patch I submitted;
-- Fixed numerous small problems with function return values.

Just informative - (no need to resend patches) - for next submissions - please add changelog to each relevant patch.

In this way one can quickly refer to the code.

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#83 lore raw

PATCH v2 3/6 GPT: add accessor function for disk GUID

In reply to alison at peloton-tech.com

Hi Alison,

Quoted 6 lines

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Quoted 156 lines
---
 cmd/gpt.c       | 30 +++++++++++++++++++++++++++++-
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 77 insertions(+), 2 deletions(-)
cmd/gpt.c +28 -1
index 3e98821..3b7d929 100644
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc
 *blk_dev_desc, const char *str_part) return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const
 namestr) +{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return 1;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return 0;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int
 argc, char * const argv[]) {
 	int ret = CMD_RET_SUCCESS;
 	int dev = 0;
-	char *ep;
+	char *ep, *varname = NULL;
 	struct blk_desc *blk_dev_desc = NULL;
 
 	if (argc < 4 || argc > 5)
@@ -436,6 +453,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag,
 int argc, char * const argv[]) } else if ((strcmp(argv[1], "verify")
 == 0)) { ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5)
+		       strcpy(varname, argv[4]);
+		return do_disk_guid(blk_dev_desc, varname);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +479,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
disk/part_efi.c +3 -0
index 20d33ef..ff9f408 100644
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header
 *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36

characters
+ */

disk/part_efi.c +3 -0
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,

dev_desc->blksz);

disk/part_efi.c +4 -0
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and

PTE */

disk/part_efi.c +6 -0
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT

***\n",

disk/part_efi.c +4 -0
+			       __func__);
+			return -1;
+		} else {
+			printf("%s: ***        Using Backup GPT

***\n",

disk/part_efi.c +10 -0
+			       __func__);
+		}
+	}
+
+	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,

dev_desc->blksz); diff --git a/doc/README.gpt b/doc/README.gpt index 3fcd835..c0779a4 100644

doc/README.gpt +0 -0
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if

CONFIG_RANDOM_UUID is enabled. A random uuid will be used if omitted or they point to an empty/ non-existent environment variable. The environment variable will be set to

doc/README.gpt +1 -1
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current

value of the
+ uuid_disk from the GPT.

The field 'bootable' is optional, it is used to mark the GPT
partition bootable (set attribute flags "Legacy BIOS bootable").

include/part.h +4 -0
index 87b1111..16c4a46 100644
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc
 *dev_desc, gpt_header *gpt_head, int gpt_verify_partitions(struct
 blk_desc *dev_desc, disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a

device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */

include/part.h int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head, · line 391

Quoted 5 lines
include/part.h +2 -0
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#84 lore raw

PATCH v2 3/6 GPT: add accessor function for disk GUID

Hi,

Quoted 11 lines · On Wed, 31 May 2017 09:44:43 +0200 Lukasz Majewski wrote:

Hi Alison,

Quoted 6 lines

From: Alison Chaiken <[email protected]>

In order to read the GPT, modify the partition name strings, and then write out a new GPT, the disk GUID is needed. While there is an existing accessor for the partition UUIDs, there is none yet for the disk GUID.

Did you read my comments on this patch in:
<[email protected]>
e.g.:

|> +		if (argc == 5)
|> +		       strcpy(varname, argv[4]);
|>  
|You didn't allocate any memory for varname and copy the argument string
|to a NULL pointer!
|Maybe use strdup() and free varname after use?

Lothar Waßmann

#85 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   8 +++++
 2 files changed, 120 insertions(+)
cmd/gpt.c +112 -0
index 3b7d929..c61d2b1 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	memset(newpart, '\0', sizeof(newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	memset(newpart->gpt_part_info.name + 31, '\0', 1);
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	memset(newpart->gpt_part_info.type + 31, '\0', 1);
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */
+	int valid_parts = 1, p, ret = 0;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
+			return -1;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (argc == 5)
 		       strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +8 -0
index 16c4a46..7d7052a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -49,6 +50,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 16
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
@@ -68,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#86 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

Quoted 27 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   8 +++++
 2 files changed, 120 insertions(+)
cmd/gpt.c +3 -0
index 3b7d929..c61d2b1 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 162

Quoted 9 lines
cmd/gpt.c +5 -0
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
 

empty line between declarations and code?

cmd/gpt.c static bool found_key(const char *str, const char *key)

Quoted 11 lines
cmd/gpt.c +10 -0
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
 

useless type cast. malloc returns a void pointer which can be assigned to any typed pointer without a cast.

cmd/gpt.c static bool found_key(const char *str, const char *key)

Quoted 3 lines
cmd/gpt.c +2 -0
+	memset(newpart, '\0', sizeof(newpart));
+	if (!newpart)
 

This NULL check should be done before the memset()!

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 180

Quoted 7 lines
cmd/gpt.c +7 -0
+		return ERR_PTR(-ENOMEM);
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	memset(newpart->gpt_part_info.name + 31, '\0', 1);
	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';

1. No need for memset here.
2. You are copying PART_NAME_LEN bytes, but set the byte at pos 31 to '\0'. => This code will blow up if PART_NAME_LEN is changed to a
different value!

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 182

Quoted 2 lines
cmd/gpt.c +2 -0
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	memset(newpart->gpt_part_info.type + 31, '\0', 1);

dto.

Quoted 29 lines
cmd/gpt.c +28 -0
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 220

Quoted 10 lines
cmd/gpt.c +10 -0
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */

s/u-boot/U-Boot/

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 221

Quoted 2 lines
cmd/gpt.c +1 -0
+	int valid_parts = 1, p, ret = 0;

No need to initialize ret here (no need to declare it here either).

Quoted 4 lines
cmd/gpt.c +3 -0
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 234

Quoted 10 lines
cmd/gpt.c +10 -0
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))

No need for () around the '>=' expression.

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 235

Quoted 1 line
cmd/gpt.c +1 -0
+			return -1;

You return -ENODEV lateron, so you should return a valid errno value here. -1 (-EPERM) is most probably not the error code you want to use here.

Quoted 13 lines
cmd/gpt.c +12 -0
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */

cmd/gpt.c static bool found_key(const char *str, const char *key) · line 258

Quoted 10 lines
cmd/gpt.c +10 -0
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;

Since the return value of this function is passed on as the exit code of the calling CMD handler it should be one of CMD_RET_SUCCESS or CMD_RET_FAILURE:

	return ret ? CMD_RET_SUCCESS : CMD_RET_FAILURE;

But see my comment below!

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 570

Quoted 10 lines
cmd/gpt.c +2 -0
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (argc == 5)
 		       strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 

If you have a careful look at the succeeding code in this function you would see, that it does not blindly pass on the return value of the functions called for each subcommand but does:

|	if (ret) {
|		printf("error!\n");
|		return CMD_RET_FAILURE;
|	}
|
|	printf("success!\n");
|	return CMD_RET_SUCCESS;

So you should just assign the return value of do_disk_guid() and do_get_gpt_info() to the variable 'ret' and let the original code handle it.

Quoted 25 lines
cmd/gpt.c +0 -0
 	} else {
 		return CMD_RET_USAGE;
cmd/gpt.c +2 -0
 	}
@@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +1 -0
index 16c4a46..7d7052a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;

include/part.h struct block_drvr { · line 54

Quoted 5 lines
include/part.h +1 -0
@@ -49,6 +50,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 16
 

Why the hard limit to 16 partitions?
A standard Android system will jump right in your face with this limit.

Lothar Waßmann

Signature · 9 lines
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
#87 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

On 2017-05-30 00:37, Lothar Waßmann wrote:
[ SNIP]

Quoted 3 lines
Quoted 1 line

+#define MAX_SEARCH_PARTITIONS 16

Why the hard limit to 16 partitions?
A standard Android system will jump right in your face with this limit.

Lothar, I'm working on making the other changes you suggested. Meanwhile, the answer to this question is that I copied the macro from a header file in 2015.07, which is the version for which I developed the
patches. I saw no equivalent value in this latest release of Das
U-Boot. Do you have a better suggestion? Is there a similar macro
elsewhere that I failed to discover?

Thanks,
Alison

---
Alison Chaiken alison at she-devel.com, 650-279-5600
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

#88 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

Quoted 6 lines · Alison

On 2017-05-30 00:37, Lothar Waßmann wrote:
[ SNIP]

Quoted 3 lines
Quoted 1 line

+#define MAX_SEARCH_PARTITIONS 16

Why the hard limit to 16 partitions?
A standard Android system will jump right in your face with this limit.

Quoted 7 lines

Lothar, I'm working on making the other changes you suggested. Meanwhile, the answer to this question is that I copied the macro from a header file in 2015.07, which is the version for which I developed the
patches. I saw no equivalent value in this latest release of Das
U-Boot. Do you have a better suggestion? Is there a similar macro
elsewhere that I failed to discover?

I'm just concerned, that the limit may be too low for a certain class of systems and see no reason why it shouldn't be set higher. There is no memory allocation involved that would consume more memory with a higher limit.

I'v seen, the macro is defined in disk/part.c. Maybe for consistency this should be defined in some header file and used in the original place and your patch.

Lothar Waßmann

Signature · 9 lines
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
#89 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

In reply to alison at peloton-tech.com

Hi Alison,

Quoted 5 lines

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

Quoted 183 lines
---
 cmd/gpt.c      | 112

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/part.h | 8 +++++ 2 files changed, 120 insertions(+)

cmd/gpt.c +31 -0
index 3b7d929..c61d2b1 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const
 char *key) return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info,
 int partnum) +{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	memset(newpart, '\0', sizeof(newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char
 *)info->name, PART_NAME_LEN);
+	memset(newpart->gpt_part_info.name + 31, '\0', 1);
+	strncpy((char *)newpart->gpt_part_info.type, (const char
 *)info->type, PART_TYPE_LEN);
+	memset(newpart->gpt_part_info.type + 31, '\0', 1);
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char

*)info->uuid,

cmd/gpt.c +16 -0
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n",

(unsigned)curr->gpt_part_info.start,

cmd/gpt.c +2 -0
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n",

curr->gpt_part_info.blksz,

cmd/gpt.c +2 -0
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n",

curr->gpt_part_info.type,

cmd/gpt.c +28 -0
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */
+	int valid_parts = 1, p, ret = 0;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info,

valid_parts);

cmd/gpt.c +4 -0
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
+			return -1;
+
+		list_add_tail(&new_disk_part->list,

&disk_partitions);

cmd/gpt.c +28 -0
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int
 argc, char * const argv[]) if (argc == 5)
 		       strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +2 -0
index 16c4a46..7d7052a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -49,6 +50,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 16
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in

partition */ @@ -68,6 +70,12 @@ typedef struct disk_partition {
#endif
} disk_partition_t;

include/part.h typedef struct disk_partition { · line 81

Quoted 9 lines
include/part.h +6 -0
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#90 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

Hi,

Quoted 10 lines · On Wed, 31 May 2017 09:48:45 +0200 Lukasz Majewski wrote:

Hi Alison,

Quoted 5 lines

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

You definitely should read other peoples comments on patches before blindly Acking them!

Lothar Waßmann

#91 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

Quoted 7 lines · On Wed, 31 May 2017 10:48:59 +0200 Lothar Waßmann <[email protected]>…

Hi,

Quoted 4 lines · On Wed, 31 May 2017 09:48:45 +0200 Lukasz Majewski wrote:

Hi Alison,

Quoted 2 lines

From: Alison Chaiken <[email protected]>

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

Make the partition table available for modification by reading it
from the user-specified device into a linked list. Provide an
accessor function for command-line testing.

You definitely should read other peoples comments on patches before blindly Acking them!

Your reply to the original thread (v1):

From: Lothar Waßmann <[email protected]>
To: alison at peloton-tech.com
Cc: u-boot at lists.denx.de, alison at she-devel.com, trini at konsulko.com

I was not added to TO/CC.

And unfortunately (from the lack of time) - I don't have time to promptly reply/see all the responses to the ML.

Alison sent v2 on Mon (to which I was added to CC).

I've assumed that this was fixed for v2. Wasn't it?

Quoted 3 lines

Lothar Waßmann

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#92 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

Quoted 27 lines · Lukasz Majewski
Quoted 7 lines · On Wed, 31 May 2017 10:48:59 +0200 Lothar Waßmann <[email protected]>…

Hi,

Quoted 4 lines · On Wed, 31 May 2017 09:48:45 +0200 Lukasz Majewski wrote:

Hi Alison,

Quoted 2 lines

From: Alison Chaiken <[email protected]>

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

Make the partition table available for modification by reading it
from the user-specified device into a linked list. Provide an
accessor function for command-line testing.

You definitely should read other peoples comments on patches before blindly Acking them!

Your reply to the original thread (v1):

From: Lothar Waßmann <[email protected]>
To: alison at peloton-tech.com
Cc: u-boot at lists.denx.de, alison at she-devel.com, trini at konsulko.com

I was not added to TO/CC.

Quoted 8 lines

And unfortunately (from the lack of time) - I don't have time to promptly reply/see all the responses to the ML.

Alison sent v2 on Mon (to which I was added to CC).

I've assumed that this was fixed for v2. Wasn't it?

I replied to his v2 patch.

Lothar Waßmann

Signature · 9 lines
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
#93 lore raw

PATCH v2 4/6 GPT: read partition table from device into a data structure

In reply to Lukasz Majewski

Hi Alison,

Quoted 9 lines

Hi Alison,

Quoted 5 lines

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it
from the user-specified device into a linked list. Provide an
accessor function for command-line testing.

Sorry, but I was to fast.

Please fix problems pointed out by Lothar.

Quoted 204 lines
Quoted 185 lines
---
 cmd/gpt.c      | 112

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/part.h | 8 +++++ 2 files changed, 120 insertions(+)

cmd/gpt.c +27 -0
index 3b7d929..c61d2b1 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+Lothar Waßmann <[email protected]>
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const
 char *key) return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part,
 list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info,
 int partnum) +{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	memset(newpart, '\0', sizeof(newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char
 *)info->name, PART_NAME_LEN);
+	memset(newpart->gpt_part_info.name + 31, '\0', 1);
+	strncpy((char *)newpart->gpt_part_info.type, (const char

*)info->type, PART_TYPE_LEN);

cmd/gpt.c +4 -0
+	memset(newpart->gpt_part_info.type + 31, '\0', 1);
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char

*)info->uuid,

cmd/gpt.c +16 -0
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n",

(unsigned)curr->gpt_part_info.start,

cmd/gpt.c +2 -0
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n",

curr->gpt_part_info.blksz,

cmd/gpt.c +2 -0
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n",

curr->gpt_part_info.type,

cmd/gpt.c +28 -0
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */
+	int valid_parts = 1, p, ret = 0;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info,

valid_parts);

cmd/gpt.c +4 -0
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
+			return -1;
+
+		list_add_tail(&new_disk_part->list,

&disk_partitions);

cmd/gpt.c +28 -0
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag,
 int argc, char * const argv[]) if (argc == 5)
 		       strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +2 -0
index 16c4a46..7d7052a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -49,6 +50,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 16
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in

partition */ @@ -68,6 +70,12 @@ typedef struct
disk_partition { #endif
} disk_partition_t;

include/part.h typedef struct disk_partition { · line 81

Quoted 9 lines
include/part.h +6 -0
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**

Best regards,

Lukasz Majewski

--

Quoted 7 lines

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
https://lists.denx.de/listinfo/u-boot

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#94 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command which is enabled via a CONFIG_CMD_GPT_FLIP option.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it renames it failed’ and renames the ‘backup’ partition as ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
via u-boot. Partitions can go to ‘backup’ only from ‘primary’ and vice-versa, only via Linux. Partitions go to ‘candidate’ from ‘primary’ or ‘backup’ only via u-boot. Only system update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 215 insertions(+), 4 deletions(-)
cmd/Kconfig +7 -0
index 5ee52f6..a8f7716 100644
@@ -575,6 +575,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +195 -4

253 lines not on this page · raw message

doc/README.gpt +13 -0
index c0779a4..e29b188 100644
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
Signature · 1 line
2.1.4
#95 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

Quoted 219 lines · alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command which is enabled via a CONFIG_CMD_GPT_FLIP option.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it renames it failed’ and renames the ‘backup’ partition as ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
via u-boot. Partitions can go to ‘backup’ only from ‘primary’ and vice-versa, only via Linux. Partitions go to ‘candidate’ from ‘primary’ or ‘backup’ only via u-boot. Only system update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 215 insertions(+), 4 deletions(-)
cmd/Kconfig +7 -0
index 5ee52f6..a8f7716 100644
@@ -575,6 +575,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +111 -4
index c61d2b1..6a0b70f 100644
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -190,16 +191,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -211,6 +229,85 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over 'partitions='.
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -222,8 +319,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -294,6 +394,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return 0;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 642

Quoted 10 lines
cmd/gpt.c +9 -0
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
 

This function should return either CMD_RET_FAILURE or CMD_RET_SUCCESS, since the return value is passed on as the exit code of the calling CMD handler function!

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 645

Quoted 4 lines
cmd/gpt.c +4 -0
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;

see above.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 656

Quoted 11 lines
cmd/gpt.c +11 -0
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;

see above.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 662

Quoted 6 lines
cmd/gpt.c +6 -0
+	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;

see above.

Quoted 6 lines
cmd/gpt.c +6 -0
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 678

Quoted 10 lines
cmd/gpt.c +10 -0
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;

see above.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 684

Quoted 6 lines
cmd/gpt.c +6 -0
+	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;

see above.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 690

Quoted 5 lines
cmd/gpt.c +5 -0
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;

see above.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 696

Quoted 6 lines
cmd/gpt.c +6 -0
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;

see above.

cmd/gpt.c static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) · line 704

Quoted 8 lines
cmd/gpt.c +8 -0
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;

see above.

Quoted 7 lines
cmd/gpt.c +3 -0
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *

cmd/gpt.c static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 755

Quoted 7 lines
cmd/gpt.c +3 -0
@@ -567,6 +749,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, varname);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
 

Either make do_flip_gpt_part() return CMD_RET_... as indicated above, or check its return value here and convert it to CMD_RET_SUCCESS or CMD_RET_FAILURE.

Also see my comment to your patch 4/6 concerning this code location.

Lothar Waßmann

Signature · 9 lines
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
#96 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

In reply to alison at peloton-tech.com

Hi Alison,

Quoted 370 lines

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command which is enabled via a CONFIG_CMD_GPT_FLIP option.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it renames it failed’ and renames the ‘backup’ partition as ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
via u-boot. Partitions can go to ‘backup’ only from ‘primary’ and vice-versa, only via Linux. Partitions go to ‘candidate’ from ‘primary’ or ‘backup’ only via u-boot. Only system update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199

+++++++++++++++++++++++++++++++++++++++++++++++++++++++--
doc/README.gpt | 13 ++++ 3 files changed, 215 insertions(+), 4 deletions(-)

cmd/Kconfig +0 -0
index 5ee52f6..a8f7716 100644
@@ -575,6 +575,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style

partition tables.

cmd/Kconfig +7 -0
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +18 -0
index c61d2b1..6a0b70f 100644
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -190,16 +191,33 @@ static struct disk_part
 *allocate_disk_part(disk_partition_t *info, int partnum) return
 newpart; }
 
+static void prettyprint_part_size(char *sizestr, unsigned long
 partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned
 long)curr->gpt_part_info.start,
+				      (unsigned long)
 curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned
 long)curr->gpt_part_info.size,
+				      (unsigned long)

curr->gpt_part_info.blksz); +

cmd/gpt.c +0 -1
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n",

(unsigned)curr->gpt_part_info.start,

cmd/gpt.c +1 -1
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr,

partsizestr); printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz, curr->gpt_part_info.name);
printf("Type %s, bootable %d\n",
curr->gpt_part_info.type, @@ -211,6 +229,85 @@ static void print_gpt_info(void) }
}

cmd/gpt.c +7 -0
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 +

strlen("partitions=uuid_disk=");

cmd/gpt.c +7 -0
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this

should be correct */

cmd/gpt.c +3 -0
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN
+ 1);
+	/* 17 because partstr in create_gpt_partitions_list() is 16

chars */

cmd/gpt.c +3 -0
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN +

1);

cmd/gpt.c +3 -0
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n",

partlistlen,

cmd/gpt.c +6 -0
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept

as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ * "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ * name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list) +{

cmd/gpt.c +11 -0
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over

'partitions='.

cmd/gpt.c +9 -0
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char

*)curr->gpt_part_info.name, PART_NAME_LEN + 1);

cmd/gpt.c +2 -0
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned

long)curr->gpt_part_info.start,

cmd/gpt.c +1 -0
+				      (unsigned long)

curr->gpt_part_info.blksz);

cmd/gpt.c +5 -0
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned

long)curr->gpt_part_info.size,

cmd/gpt.c +1 -0
+				      (unsigned long)

curr->gpt_part_info.blksz);

cmd/gpt.c +4 -0
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char

*)curr->gpt_part_info.uuid,

cmd/gpt.c +44 -2
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -222,8 +319,11 @@ static int get_gpt_info(struct blk_desc
 *dev_desc) disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -294,6 +394,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc
 *dev_desc, char * const namestr) return 0;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n",
 numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *)
 disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %d chars\n",

partitions_list, strlen(partitions_list)); +

cmd/gpt.c +1 -0
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list,

&str_disk_guid,

cmd/gpt.c +7 -0
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name,

"backup_kernel"))

cmd/gpt.c +1 -0
+			strcpy((char *)curr->gpt_part_info.name,

"candidate_kernel");

cmd/gpt.c +1 -0
+		if (!strcmp((char *)curr->gpt_part_info.name,

"primary_kernel"))

cmd/gpt.c +1 -0
+			strcpy((char *)curr->gpt_part_info.name,

"backup_kernel");

cmd/gpt.c +1 -0
+		if (!strcmp((char *)curr->gpt_part_info.name,

"backup_rootfs"))

cmd/gpt.c +1 -0
+			strcpy((char *)curr->gpt_part_info.name,

"candidate_rootfs");

cmd/gpt.c +1 -0
+		if (!strcmp((char *)curr->gpt_part_info.name,

"primary_rootfs"))

cmd/gpt.c +1 -0
+			strcpy((char *)curr->gpt_part_info.name,

"backup_rootfs");

cmd/gpt.c +3 -0
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *)

disk_guid, partitions_list);

cmd/gpt.c +3 -0
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %d chars\n",

partitions_list, strlen(partitions_list)); +

cmd/gpt.c +1 -0
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list,

&str_disk_guid,

cmd/gpt.c +6 -0
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions,

numparts);

cmd/gpt.c +10 -0
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n",

numparts);

cmd/gpt.c +18 -0
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -567,6 +749,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag,
 int argc, char * const argv[]) return do_disk_guid(blk_dev_desc,
 varname); } else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -598,4 +784,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_FLIP
+	"gpt partition-flip command\n"
+	"gpt flip <interface> <dev>\n"
+	"    - exchange device's 'primary' and 'backup' partition

names\n" +#endif
);

doc/README.gpt +0 -0
index c0779a4..e29b188 100644
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT

verification has succeed: U-BOOT> gpt verify mmc 0 $partitions
U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi

doc/README.gpt +4 -0
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot

can +communicate about software updates and boot failure. The 'gpt guid', +'gpt read' and 'gpt flip' commands facilitate programmatic renaming of +partitions from bootscripts by generating and modifying the partitions +layout string. The code in gpt_flip() illustrates the case of +swapping 'primary' and 'backup' partitions via:

doc/README.gpt

Quoted 2 lines
doc/README.gpt +2 -0
+
+U-BOOT> gpt flip mmc 0

Maybe it would be better to have

gpt flip mmc 0 <optional parameter 'name'>

(By default we have "primary" and "backup")

In that way we could set other names to GPT partitions without the need to modify the code.

And another request -> Could you consider adding tests for those new gpt commands to the 'sandbox' (sandbox_defconfig) ?

Then you can 'mount' some gpt test image ('host' command) and use it with:
gpt <command> host X .....

Despite above comments - you did a great job :-)

doc/README.gpt Following line can be used to assess if GPT verification has succeed: · line 228

Quoted 5 lines
doc/README.gpt +2 -0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#97 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

On 2017-05-31 01:12, Lukasz Majewski wrote:

[ SNIP ]

Quoted 8 lines

Maybe it would be better to have

gpt flip mmc 0 <optional parameter 'name'>

(By default we have "primary" and "backup")

In that way we could set other names to GPT partitions without the need to modify the code.

Another possibility is to support

gpt flip mmc 0 <name 1> <name 2>

where two names are required, with defaults 'primary' and 'backup'. Perhaps I should rework patch 5 that way? I considered this form for the original submission, but wasn't sure what other projects might find useful.

Quoted 2 lines

And another request -> Could you consider adding tests for those new gpt commands to the 'sandbox' (sandbox_defconfig) ?

I will look into adding another patch to do that. I'm sure such tests
are a good idea for our project.

Quoted 1 line

Despite above comments - you did a great job :-)

Thanks. I'm sorry to have omitted you, Lukasz, from the original
submission, but I consulted an old version of MAINTAINERS from my original 2015.07.

-- Alison

---
Alison Chaiken alison at she-devel.com, 650-279-5600
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

#98 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

Hi Alison,

Quoted 13 lines · Lukasz Majewski

[ SNIP ]

Quoted 8 lines

Maybe it would be better to have

gpt flip mmc 0 <optional parameter 'name'>

(By default we have "primary" and "backup")

In that way we could set other names to GPT partitions without the need to modify the code.

Quoted 6 lines

Another possibility is to support

gpt flip mmc 0 <name 1> <name 2>

where two names are required, with defaults 'primary' and 'backup'. Perhaps I should rework patch 5 that way?

Please correct my understanding if I'm wrong.

You parse GPT partitions to a list and there are only two names possible:

"primary" and "backup".

When we call gpt filp we rename those names ("primary" -> "backup" and the other way).

Ahhh..... so your patch would allow to rename "primary" to <name1> and "backup" to <name2> for all names.

My idea was rather to have a gpt call to set name of a GPT partition....

Quoted 3 lines

I considered this form for
the original submission, but wasn't sure what other projects might find useful.

I can image that somebody would like to change on the fly single GPT partition name (when having/care about 2 partitions for his/her project specific data).

But, I don't know how much effort it would take to implement it (and if others would see it beneficial).

Quoted 6 lines
Quoted 3 lines

And another request -> Could you consider adding tests for those new gpt commands to the 'sandbox' (sandbox_defconfig) ?

I will look into adding another patch to do that. I'm sure such
tests are a good idea for our project.

It is relatively easy to use sandbox to test some high level stuff (like file systems, gpt, etc). One don't need HW for it.

Quoted 6 lines
Quoted 2 lines

Despite above comments - you did a great job :-)

Thanks. I'm sorry to have omitted you, Lukasz, from the original
submission, but I consulted an old version of MAINTAINERS from my original 2015.07.

It's Ok, don't worry. Things like that do happen....

Quoted 8 lines

-- Alison

---
Alison Chaiken alison at she-devel.com, 650-279-5600
http://{ she-devel.com, exerciseforthereader.org } "We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#99 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

Quoted 8 lines · Lukasz Majewski

Maybe it would be better to have

gpt flip mmc 0 <optional parameter 'name'>

(By default we have "primary" and "backup")

In that way we could set other names to GPT partitions without the need to modify the code.

I answered:

Quoted 6 lines
Quoted 6 lines

Another possibility is to support

gpt flip mmc 0 <name 1> <name 2>

where two names are required, with defaults 'primary' and 'backup'. Perhaps I should rework patch 5 that way?

Lukasz responded:

Quoted 13 lines

Please correct my understanding if I'm wrong.

You parse GPT partitions to a list and there are only two names possible:

"primary" and "backup".

When we call gpt filp we rename those names ("primary" -> "backup" and the other way).

Ahhh..... so your patch would allow to rename "primary" to <name1> and "backup" to <name2> for all names.

Quoted 8 lines

My idea was rather to have a gpt call to set name of a GPT partition....

I can image that somebody would like to change on the fly single GPT partition name (when having/care about 2 partitions for his/her project specific data).

But, I don't know how much effort it would take to implement it (and if others would see it beneficial).

I would propose then two options:

gpt rename mmc 0 <name 1> <name 2>

which renames all the 1's to 2's, and

gpt flip mmc 0 <name 1> <name 2>

which swaps the two name strings for all partitions where they're found.
These two operations together with 'gpt write' then cover all the
common use cases I can imagine.

I'm open to any other suggestions, of course. I just posted what I
already had to get started.

-- Alison

---
Alison Chaiken alison at she-devel.com, 650-279-5600
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

#100 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

Hi Alison,

Quoted 49 lines
Quoted 8 lines · Lukasz Majewski

Maybe it would be better to have

gpt flip mmc 0 <optional parameter 'name'>

(By default we have "primary" and "backup")

In that way we could set other names to GPT partitions without the need to modify the code.

I answered:

Quoted 6 lines
Quoted 6 lines

Another possibility is to support

gpt flip mmc 0 <name 1> <name 2>

where two names are required, with defaults 'primary' and 'backup'. Perhaps I should rework patch 5 that way?

Lukasz responded:

Quoted 16 lines

Please correct my understanding if I'm wrong.

You parse GPT partitions to a list and there are only two names possible:

"primary" and "backup".

When we call gpt filp we rename those names ("primary" -> "backup" and the other way).

Ahhh..... so your patch would allow to rename "primary" to <name1> and "backup" to <name2> for all names.

My idea was rather to have a gpt call to set name of a GPT partition....

Quoted 6 lines

I can image that somebody would like to change on the fly single GPT partition name (when having/care about 2 partitions for his/her project specific data).

But, I don't know how much effort it would take to implement it (and if others would see it beneficial).

I would propose then two options:

gpt rename mmc 0 <name 1> <name 2>

Quoted 7 lines

which renames all the 1's to 2's, and

gpt flip mmc 0 <name 1> <name 2>

which swaps the two name strings for all partitions where they're found. These two operations together with 'gpt write' then cover all the common use cases I can imagine.

I think that this is enough. Let's wait for other's opinions (if any).

Quoted 11 lines

I'm open to any other suggestions, of course. I just posted what I
already had to get started.

-- Alison

---
Alison Chaiken alison at she-devel.com,
650-279-5600 http://{ she-devel.com, exerciseforthereader.org } "We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#101 lore raw

v4 cover add support for GPT partition name manipulation

In reply to Lukasz Majewski

From: Alison Chaiken <[email protected]>

One way for userspace and the bootloader to exchange information about dynamic image selection is via the storage device partition table, as described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag. When no partition on a device is bootable since the kernel and U-Boot are stored elsewhere, the name field in the GPT partition table offers another logical place to store information. These patches allow users to easily modify GPT partition names via bootscripts that can select different images based on a boot-failure counter, or when userspace installs a software update.

These patches have been tested in the u-boot sandbox and (re)tested on a TI DRA7xx-based SOM with U-Boot 2015.07.

Significant changes since v3:
-- Testing in sandbox showed error in NULL termination of UUID string
in cmd/gpt.c. That problem is fixed in 0001-GPT-read-partition-table-from-device-into-a-data-str.patch.
-- Patch 3 "GPT: fix error in partitions string doc" now only treats
the topic in the commit title, as the part dealing with the proposed 'flip' feature is moved to that patch.
-- Two new commits come from testing in the sandbox (of which I was
previously unaware). One fixes an error in README.sandbox, and
one adds a few comments about sandbox testing to README.gpt.

Significant changes since v2:
-- Got rid of the need to allocate memory for the GUID string in
do_gpt();
-- Fixed the problems with string NULL termination in
allocate_disk_part();
-- Removed duplicate definition of MAX_SEARCH_PARTITIONS from
disk/part.c and increased the value in include/part.h to 64;
-- Improved the commit message for "rename GPT partitions to detect
boot failure" to better describe the version of the patch I submitted;
-- Fixed numerous small problems with function return values.

Significant changes since v1:
-- Put the gpt_flip() function and auxiliary ones inside a new
CONFIG_CMD_GPT_FLIP option that depends on CMD_GPT.
-- Replace intentional overwriting of name and type string arrays with
memset() instead.
-- Move part.h changes earlier in the patchset.
-- Add a few lines to README.gpt about the new gpt subcommands.

Added a few simple patches to do the following:
-- Replace remaining occurrences of '37' with UUID_STR_LEN+1; -- Introduce new macros to get rid of the similar '32'; -- fix a smaller error in doc/README.gpt.

There are also some fixups of whitespace and formatting errors (plus usual inevitable addition of new ones).

To do in future:
-- Add support for preserving the type flag for partitions. The u-boot
version on which this patchset is based did not have this feature, and it's easy to add, but I need to figure how to test it first.

-- Add tests for the new gpt commands to the sandbox.

Alison Chaiken (5):
GPT: read partition table from device into a data structure rename GPT partitions to detect boot failure
GPT: fix error in partitions string doc
sandbox: README: fix partition command invocation cmd gpt: test in sandbox

 board/sandbox/README.sandbox |   2 +-
 cmd/Kconfig                  |   7 +
 cmd/gpt.c                    | 298 +++++++++++++++++++++++++++++++++++++++++++
 doc/README.gpt               |  31 ++++-
 include/part.h               |   7 +
 5 files changed, 340 insertions(+), 5 deletions(-)
Signature · 1 line
2.1.4
#102 lore raw

PATCH v4 1/5 GPT: read partition table from device into a data structure

From: Alison Chaiken <[email protected]>

Make the partition table available for modification by reading it from
the user-specified device into a linked list. Provide an accessor
function for command-line testing.

Changes since v3:
Fixed problem with NULL termination of the newly created uuid[]
member of the partitions list in allocate_disk_part. This
version has been tested in the u-boot sandbox.

---
 cmd/gpt.c      | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 123 insertions(+)
cmd/gpt.c +116 -0
index 4d00a35..e898f35 100644
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,115 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && valid_parts >= 2)
+			return -ENODEV;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +567,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		return do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +591,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
include/part.h +7 -0
index c41aa6a..0cd803a 100644
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
Signature · 1 line
2.1.4
#103 lore raw

PATCH v4 2/5 rename GPT partitions to detect boot failure

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

This patch provides support in u-boot for renaming GPT partitions. The renaming is accomplished via a new 'gpt flip' command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions end up with "msftdata" flag set. The reason is that partition type PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte() function. This does not appear to cause any harm.

Changes since v3:
-- Squashed changes to comments that had been made in a different
patch into this one.
-- Fixed lines over 80 chars.
-- Tested in u-boot sandbox.

---
 cmd/Kconfig    |   7 +++
 cmd/gpt.c      | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 206 insertions(+), 4 deletions(-)
cmd/Kconfig +7 -0
index 6f75b86..8b925e5 100644
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
cmd/gpt.c +186 -4

244 lines not on this page · raw message

doc/README.gpt +13 -0
index c0779a4..e29b188 100644
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
Signature · 1 line
2.1.4
#104 lore raw

PATCH v4 3/5 GPT: fix error in partitions string doc

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt accordingly.

Changes since v3:
-- The part of this patch dealing with the partition-flipping
behavior was squashed into the patch that introduces that feature.

---
 doc/README.gpt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
doc/README.gpt +4 -4
index e29b188..754e490 100644
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -255,7 +255,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
Signature · 1 line
2.1.4
#105 lore raw

PATCH v4 4/5 sandbox: README: fix partition command invocation

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

The instructions for creating a disk image that are presently in README.sandbox fail because sfdisk doesn't know about GPT.

---
 board/sandbox/README.sandbox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
board/sandbox/README.sandbox +1 -1
index 02d8ab3..9dc2eb0 100644
@@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image
 A disk image can be created using the following commands:
 
 $> truncate -s 1200M ./disk.raw
-$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk  ./disk.raw
+$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk  ./disk.raw
 $> lodev=`sudo losetup -P -f --show ./disk.raw`
 $> sudo mkfs.vfat -n EFI -v ${lodev}p1
 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
Signature · 1 line
2.1.4
#106 lore raw

PATCH 4/5 sandbox: README: fix partition command invocation

Quoted 15 lines · On 4 June 2017 at 16:11, <[email protected]> wrote:

From: Alison Chaiken <[email protected]>

The instructions for creating a disk image that are presently in README.sandbox fail because sfdisk doesn't know about GPT.

---
 board/sandbox/README.sandbox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
board/sandbox/README.sandbox +0 -0
index 02d8ab3..9dc2eb0 100644

board/sandbox/README.sandbox the contents of the root directory on the second partion of the image · line 339

Quoted 8 lines
board/sandbox/README.sandbox +1 -1
@@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image
 A disk image can be created using the following commands:
 
 $> truncate -s 1200M ./disk.raw
-$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk  ./disk.raw
+$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk  ./disk.raw
 $> lodev=`sudo losetup -P -f --show ./disk.raw`
 $> sudo mkfs.vfat -n EFI -v ${lodev}p1
 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2

Tested on Ubuntu 14.04 (with tools in /sbin):

Quoted 7 lines

--
2.1.4

_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
https://lists.denx.de/listinfo/u-boot

#107 lore raw

PATCH 4/5 sandbox: README: fix partition command invocation

Quoted 10 lines · On 4 June 2017 at 16:11, <[email protected]> wrote:

From: Alison Chaiken <[email protected]>

The instructions for creating a disk image that are presently in README.sandbox fail because sfdisk doesn't know about GPT.

---
 board/sandbox/README.sandbox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Applied to u-boot-dm, thanks!

#108 lore raw

PATCH v4 5/5 cmd gpt: test in sandbox

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

Make minor changes to README.gpt and sandbox_defconfig to support testing of the gpt command's functionality in the sandbox.

---
 doc/README.gpt | 10 ++++++++++
 1 file changed, 10 insertions(+)
doc/README.gpt +10 -0
index 754e490..7b3936b 100644
@@ -224,6 +224,16 @@ U-BOOT> gpt flip mmc 0
 
 Choose different partition names by modifying these strings in gpt.c.
 
+The GPT functionality may be tested with the 'sandbox' board by
+creating a disk image as described under 'Block Device Emulation' in
+board/sandbox/README.sandbox:
+
+=>host bind 0 ./disk.raw
+=> gpt read host 0
+[ . . . ]
+=> gpt flip host 0
+[ . . . ]
+
 Partition type GUID:
 ====================
 
Signature · 1 line
2.1.4
#110 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

In reply to Lukasz Majewski

On 2017-05-31 01:12, Lukasz Majewski wrote:

[ . . . ]

Quoted 6 lines

And another request -> Could you consider adding tests for those new gpt commands to the 'sandbox' (sandbox_defconfig) ?

Then you can 'mount' some gpt test image ('host' command) and use it with:
gpt <command> host X .....

The GPT functionality really cannot be tested without a block device. We could build the disk.raw described in board/sandbox/README.sandbox when (CONFIG_UNIT_TEST && CONFIG_CMD_GPT_RENAME) in imitation of the
file helloworld.efi. There would be no reason for the size to be as
large as 1200M, of course. 256KB appears to be the smallest usable
size for 4 partitions (although trying to partition a 16 KB raw object with gdisk produces entertaining results).

To create this object for testing, we could use a subdirectory like lib/efi_loader, but maybe doing so in test/ makes more sense? If the build system did create the object, then we could modify
board/sandbox/README.sandbox to so indicate. Then the test should go
in test/py/tests presumably.

Thanks for feedback,
Alison

---
Alison Chaiken alison at she-devel.com
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

#111 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

Quoted 19 lines · Alison

On 2017-05-31 01:12, Lukasz Majewski wrote:

[ . . . ]

Quoted 6 lines

And another request -> Could you consider adding tests for those new gpt commands to the 'sandbox' (sandbox_defconfig) ?

Then you can 'mount' some gpt test image ('host' command) and use it with:
gpt <command> host X .....

The GPT functionality really cannot be tested without a block device. We could build the disk.raw described in board/sandbox/README.sandbox when (CONFIG_UNIT_TEST && CONFIG_CMD_GPT_RENAME) in imitation of the
file helloworld.efi. There would be no reason for the size to be as
large as 1200M, of course. 256KB appears to be the smallest usable
size for 4 partitions (although trying to partition a 16 KB raw object with gdisk produces entertaining results).

Quoted 5 lines

To create this object for testing, we could use a subdirectory like lib/efi_loader, but maybe doing so in test/ makes more sense? If the build system did create the object, then we could modify
board/sandbox/README.sandbox to so indicate. Then the test should go
in test/py/tests presumably.

If you have encountered some issues with adding this test to sandbox (and those are difficult to solve), then it would be also correct to add this test to test/py and run it on a real HW.

Please also keep in mind to provide some kind of verbose in-code description or proper documentation entry.

Quoted 10 lines

Thanks for feedback,
Alison

---
Alison Chaiken alison at she-devel.com
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos Simoudis

Signature · 9 lines
Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
#112 lore raw

PATCH v2 5/6 rename GPT partitions to detect boot failure

Quoted 26 lines · Å�ukasz Majewski
Quoted 19 lines · Alison

On 2017-05-31 01:12, Lukasz Majewski wrote:

[ . . . ]

Quoted 6 lines

And another request -> Could you consider adding tests for those new gpt commands to the 'sandbox' (sandbox_defconfig) ?

Then you can 'mount' some gpt test image ('host' command) and use it with:
gpt <command> host X .....

The GPT functionality really cannot be tested without a block device. We could build the disk.raw described in board/sandbox/README.sandbox when (CONFIG_UNIT_TEST && CONFIG_CMD_GPT_RENAME) in imitation of the
file helloworld.efi. There would be no reason for the size to be as
large as 1200M, of course. 256KB appears to be the smallest usable
size for 4 partitions (although trying to partition a 16 KB raw object with gdisk produces entertaining results).

Quoted 5 lines

To create this object for testing, we could use a subdirectory like lib/efi_loader, but maybe doing so in test/ makes more sense? If the build system did create the object, then we could modify
board/sandbox/README.sandbox to so indicate. Then the test should go
in test/py/tests presumably.

Quoted 3 lines

If you have encountered some issues with adding this test to sandbox (and those are difficult to solve), then it would be also correct to add this test to test/py and run it on a real HW.

Right. Everyone can run test.py on sandbox _and_ QEMU, and there are then some people with labs setup that also run test.py on real hardware. Between QEMU and real hardware we should be able to add and run tests for this. Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170828/3b6b97d8/attachment.sig>
#113 lore raw

PATCH v2 6/6 GPT: fix error in partitions string doc

In reply to alison at peloton-tech.com

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt and file comments accordingly.

---
 cmd/gpt.c      | 13 +------------
 doc/README.gpt |  8 ++++----
 2 files changed, 5 insertions(+), 16 deletions(-)
cmd/gpt.c +1 -12
index 6a0b70f..487314b 100644
@@ -232,12 +232,6 @@ static void print_gpt_info(void)
 #ifdef CONFIG_CMD_GPT_FLIP
 static int calc_parts_list_len(int numparts)
 {
-	/*
-	 * prefatory string:
-	 * doc/README.GPT, suggests that
-	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
-	 * is correct, but extract_val() expects "uuid_disk" first.
-	 */
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
 	/* for the comma */
 	partlistlen++;
@@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
  * argument
  *
  * From doc/README.gpt, Format of partitions layout:
- *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
  *	name=kernel,size=60MiB,uuid=...;"
  * The fields 'name' and 'size' are mandatory for every partition.
  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
@@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int numparts, const char *guid, char *part
 	if (!partitions_list)
 		return -1;
 
-	/*
-	 * README.gpt specifies starting with "partitions=" like so:
-	 *      strcpy(partitions_list, "partitions=uuid_disk=");
-	 * but that breaks extract_val, which doesn't skip over 'partitions='.
-	 */
 	strcpy(partitions_list, "uuid_disk=");
 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
 	strcat(partitions_list, ";");
doc/README.gpt +4 -4
index e29b188..754e490 100644
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -255,7 +255,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
Signature · 1 line
2.1.4
#114 lore raw

PATCH v2 6/6 GPT: fix error in partitions string doc

Hi Alison,

Quoted 8 lines

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt and file comments accordingly.

Thank you for updating the README.gpt entry.

Quoted 82 lines
---
 cmd/gpt.c      | 13 +------------
 doc/README.gpt |  8 ++++----
 2 files changed, 5 insertions(+), 16 deletions(-)
cmd/gpt.c +0 -6
index 6a0b70f..487314b 100644
@@ -232,12 +232,6 @@ static void print_gpt_info(void)
 #ifdef CONFIG_CMD_GPT_FLIP
 static int calc_parts_list_len(int numparts)
 {
-	/*
-	 * prefatory string:
-	 * doc/README.GPT, suggests that
-	 * int partlistlen = UUID_STR_LEN + 1 +
 strlen("partitions=uuid_disk=");
-	 * is correct, but extract_val() expects "uuid_disk" first.
-	 */
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
 	/* for the comma */
cmd/gpt.c +1 -5
 	partlistlen++;
@@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
  * argument
  *
  * From doc/README.gpt, Format of partitions layout:
- *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
  *	name=kernel,size=60MiB,uuid=...;"
  * The fields 'name' and 'size' are mandatory for every partition.
  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
@@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int
 numparts, const char *guid, char *part if (!partitions_list)
 		return -1;
 
-	/*
-	 * README.gpt specifies starting with "partitions=" like so:
-	 *      strcpy(partitions_list, "partitions=uuid_disk=");
-	 * but that breaks extract_val, which doesn't skip over

'partitions='.

cmd/gpt.c +0 -1
-	 */
 	strcpy(partitions_list, "uuid_disk=");
 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
 	strcat(partitions_list, ";");
doc/README.gpt +2 -2
index e29b188..754e490 100644
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID

(EBD0A0A2-B9E5-4433-87C0-68B6B72699C7). If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type' can specify a other partition type guid:

doc/README.gpt +1 -1
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
@@ -255,7 +255,7 @@ Some strings can be also used at the place of

known GUID : "lvm" = PARTITION_LINUX_LVM_GUID

doc/README.gpt +1 -1
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list"
Quoted 1 line

command.

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

#115 lore raw

PATCH v2 6/6 GPT: fix error in partitions string doc

Hi Alison,

Quoted 11 lines

Hi Alison,

Quoted 8 lines

From: Alison Chaiken <[email protected]>

The existing partitions-list parsing in cmd/gpt.c passes a value from gpt_default() to set_gpt_info() that README.gpt suggests should begin with 'partitions='. Partition-list strings should in fact begin with 'uuid_disk', as otherwise the call from set_gpt_info() to extract_val() to find 'uuid_disk' will fail. Change README.gpt and file comments accordingly.

Quoted 3 lines

Thank you for updating the README.gpt entry.

Please also use either patman or get_maintainer before sending the patchset.

For exmaple:
./scripts/get_maintainer.pl 0001-wip.patch

In that way all relevant people would be informed :-)

Quoted 91 lines
Quoted 84 lines
---
 cmd/gpt.c      | 13 +------------
 doc/README.gpt |  8 ++++----
 2 files changed, 5 insertions(+), 16 deletions(-)
cmd/gpt.c +0 -6
index 6a0b70f..487314b 100644
@@ -232,12 +232,6 @@ static void print_gpt_info(void)
 #ifdef CONFIG_CMD_GPT_FLIP
 static int calc_parts_list_len(int numparts)
 {
-	/*
-	 * prefatory string:
-	 * doc/README.GPT, suggests that
-	 * int partlistlen = UUID_STR_LEN + 1 +
 strlen("partitions=uuid_disk=");
-	 * is correct, but extract_val() expects "uuid_disk" first.
-	 */
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
 	/* for the comma */
cmd/gpt.c +1 -3
 	partlistlen++;
@@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
  * argument
  *
  * From doc/README.gpt, Format of partitions layout:
- *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
  *	name=kernel,size=60MiB,uuid=...;"
  * The fields 'name' and 'size' are mandatory for every partition.
  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
@@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int
 numparts, const char *guid, char *part if (!partitions_list)
 		return -1;
 
-	/*
-	 * README.gpt specifies starting with "partitions=" like

so:

cmd/gpt.c +0 -2
-	 *      strcpy(partitions_list, "partitions=uuid_disk=");
-	 * but that breaks extract_val, which doesn't skip over

'partitions='.

cmd/gpt.c +0 -1
-	 */
 	strcpy(partitions_list, "uuid_disk=");
 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
 	strcat(partitions_list, ";");
doc/README.gpt +2 -2
index e29b188..754e490 100644
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID

(EBD0A0A2-B9E5-4433-87C0-68B6B72699C7). If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type' can specify a other partition type guid:

doc/README.gpt +1 -1
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
@@ -255,7 +255,7 @@ Some strings can be also used at the place of

known GUID : "lvm" = PARTITION_LINUX_LVM_GUID

doc/README.gpt +1 -1
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list"
Quoted 1 line

command.

Best regards,

Quoted 7 lines

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de