Home | History | Annotate | Download | only in cmd
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * cmd_gpt.c -- GPT (GUID Partition Table) handling command
      4  *
      5  * Copyright (C) 2015
      6  * Lukasz Majewski <l.majewski (at) majess.pl>
      7  *
      8  * Copyright (C) 2012 Samsung Electronics
      9  * author: Lukasz Majewski <l.majewski (at) samsung.com>
     10  * author: Piotr Wilczek <p.wilczek (at) samsung.com>
     11  */
     12 
     13 #include <common.h>
     14 #include <malloc.h>
     15 #include <command.h>
     16 #include <part_efi.h>
     17 #include <exports.h>
     18 #include <linux/ctype.h>
     19 #include <div64.h>
     20 #include <memalign.h>
     21 #include <linux/compat.h>
     22 #include <linux/sizes.h>
     23 #include <stdlib.h>
     24 
     25 static LIST_HEAD(disk_partitions);
     26 
     27 /**
     28  * extract_env(): Expand env name from string format '&{env_name}'
     29  *                and return pointer to the env (if the env is set)
     30  *
     31  * @param str - pointer to string
     32  * @param env - pointer to pointer to extracted env
     33  *
     34  * @return - zero on successful expand and env is set
     35  */
     36 static int extract_env(const char *str, char **env)
     37 {
     38 	int ret = -1;
     39 	char *e, *s;
     40 #ifdef CONFIG_RANDOM_UUID
     41 	char uuid_str[UUID_STR_LEN + 1];
     42 #endif
     43 
     44 	if (!str || strlen(str) < 4)
     45 		return -1;
     46 
     47 	if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')))
     48 		return -1;
     49 
     50 	s = strdup(str);
     51 	if (s == NULL)
     52 		return -1;
     53 
     54 	memset(s + strlen(s) - 1, '\0', 1);
     55 	memmove(s, s + 2, strlen(s) - 1);
     56 
     57 	e = env_get(s);
     58 	if (e == NULL) {
     59 #ifdef CONFIG_RANDOM_UUID
     60 		debug("%s unset. ", str);
     61 		gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID);
     62 		env_set(s, uuid_str);
     63 
     64 		e = env_get(s);
     65 		if (e) {
     66 			debug("Set to random.\n");
     67 			ret = 0;
     68 		} else {
     69 			debug("Can't get random UUID.\n");
     70 		}
     71 #else
     72 		debug("%s unset.\n", str);
     73 #endif
     74 	} else {
     75 		debug("%s get from environment.\n", str);
     76 		ret = 0;
     77 	}
     78 
     79 	*env = e;
     80 	free(s);
     81 
     82 	return ret;
     83 }
     84 
     85 /**
     86  * extract_val(): Extract value from a key=value pair list (comma separated).
     87  *                Only value for the given key is returend.
     88  *                Function allocates memory for the value, remember to free!
     89  *
     90  * @param str - pointer to string with key=values pairs
     91  * @param key - pointer to the key to search for
     92  *
     93  * @return - pointer to allocated string with the value
     94  */
     95 static char *extract_val(const char *str, const char *key)
     96 {
     97 	char *v, *k;
     98 	char *s, *strcopy;
     99 	char *new = NULL;
    100 
    101 	strcopy = strdup(str);
    102 	if (strcopy == NULL)
    103 		return NULL;
    104 
    105 	s = strcopy;
    106 	while (s) {
    107 		v = strsep(&s, ",");
    108 		if (!v)
    109 			break;
    110 		k = strsep(&v, "=");
    111 		if (!k)
    112 			break;
    113 		if  (strcmp(k, key) == 0) {
    114 			new = strdup(v);
    115 			break;
    116 		}
    117 	}
    118 
    119 	free(strcopy);
    120 
    121 	return new;
    122 }
    123 
    124 /**
    125  * found_key(): Found key without value in parameter list (comma separated).
    126  *
    127  * @param str - pointer to string with key
    128  * @param key - pointer to the key to search for
    129  *
    130  * @return - true on found key
    131  */
    132 static bool found_key(const char *str, const char *key)
    133 {
    134 	char *k;
    135 	char *s, *strcopy;
    136 	bool result = false;
    137 
    138 	strcopy = strdup(str);
    139 	if (!strcopy)
    140 		return NULL;
    141 
    142 	s = strcopy;
    143 	while (s) {
    144 		k = strsep(&s, ",");
    145 		if (!k)
    146 			break;
    147 		if  (strcmp(k, key) == 0) {
    148 			result = true;
    149 			break;
    150 		}
    151 	}
    152 
    153 	free(strcopy);
    154 
    155 	return result;
    156 }
    157 
    158 static int calc_parts_list_len(int numparts)
    159 {
    160 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
    161 	/* for the comma */
    162 	partlistlen++;
    163 
    164 	/* per-partition additions; numparts starts at 1, so this should be correct */
    165 	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
    166 	/* see part.h for definition of struct disk_partition */
    167 	partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1);
    168 	partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1);
    169 	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
    170 	/* for the terminating null */
    171 	partlistlen++;
    172 	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
    173 	      numparts);
    174 	return partlistlen;
    175 }
    176 
    177 #ifdef CONFIG_CMD_GPT_RENAME
    178 static void del_gpt_info(void)
    179 {
    180 	struct list_head *pos = &disk_partitions;
    181 	struct disk_part *curr;
    182 	while (!list_empty(pos)) {
    183 		curr = list_entry(pos->next, struct disk_part, list);
    184 		list_del(pos->next);
    185 		free(curr);
    186 	}
    187 }
    188 
    189 static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
    190 {
    191 	struct disk_part *newpart;
    192 	newpart = calloc(1, sizeof(struct disk_part));
    193 	if (!newpart)
    194 		return ERR_PTR(-ENOMEM);
    195 
    196 	newpart->gpt_part_info.start = info->start;
    197 	newpart->gpt_part_info.size = info->size;
    198 	newpart->gpt_part_info.blksz = info->blksz;
    199 	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
    200 		PART_NAME_LEN);
    201 	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
    202 	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
    203 		PART_TYPE_LEN);
    204 	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
    205 	newpart->gpt_part_info.bootable = info->bootable;
    206 #ifdef CONFIG_PARTITION_UUIDS
    207 	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
    208 		UUID_STR_LEN);
    209 	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
    210 	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
    211 #endif
    212 	newpart->partnum = partnum;
    213 
    214 	return newpart;
    215 }
    216 
    217 static void prettyprint_part_size(char *sizestr, lbaint_t partsize,
    218 				  lbaint_t blksize)
    219 {
    220 	unsigned long long partbytes, partmegabytes;
    221 
    222 	partbytes = partsize * blksize;
    223 	partmegabytes = lldiv(partbytes, SZ_1M);
    224 	snprintf(sizestr, 16, "%lluMiB", partmegabytes);
    225 }
    226 
    227 static void print_gpt_info(void)
    228 {
    229 	struct list_head *pos;
    230 	struct disk_part *curr;
    231 	char partstartstr[16];
    232 	char partsizestr[16];
    233 
    234 	list_for_each(pos, &disk_partitions) {
    235 		curr = list_entry(pos, struct disk_part, list);
    236 		prettyprint_part_size(partstartstr, curr->gpt_part_info.start,
    237 				      curr->gpt_part_info.blksz);
    238 		prettyprint_part_size(partsizestr, curr->gpt_part_info.size,
    239 				      curr->gpt_part_info.blksz);
    240 
    241 		printf("Partition %d:\n", curr->partnum);
    242 		printf("Start %s, size %s\n", partstartstr, partsizestr);
    243 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
    244 		       curr->gpt_part_info.name);
    245 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
    246 		       curr->gpt_part_info.bootable);
    247 #ifdef CONFIG_PARTITION_UUIDS
    248 		printf("UUID %s\n", curr->gpt_part_info.uuid);
    249 #endif
    250 		printf("\n");
    251 	}
    252 }
    253 
    254 /*
    255  * create the string that upstream 'gpt write' command will accept as an
    256  * argument
    257  *
    258  * From doc/README.gpt, Format of partitions layout:
    259  *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
    260  *	name=kernel,size=60MiB,uuid=...;"
    261  * The fields 'name' and 'size' are mandatory for every partition.
    262  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
    263  * are optional if CONFIG_RANDOM_UUID is enabled.
    264  */
    265 static int create_gpt_partitions_list(int numparts, const char *guid,
    266 				      char *partitions_list)
    267 {
    268 	struct list_head *pos;
    269 	struct disk_part *curr;
    270 	char partstr[PART_NAME_LEN + 1];
    271 
    272 	if (!partitions_list)
    273 		return -EINVAL;
    274 
    275 	strcpy(partitions_list, "uuid_disk=");
    276 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
    277 	strcat(partitions_list, ";");
    278 
    279 	list_for_each(pos, &disk_partitions) {
    280 		curr = list_entry(pos, struct disk_part, list);
    281 		strcat(partitions_list, "name=");
    282 		strncat(partitions_list, (const char *)curr->gpt_part_info.name,
    283 			PART_NAME_LEN + 1);
    284 		sprintf(partstr, ",start=0x%llx",
    285 			(unsigned long long)curr->gpt_part_info.start *
    286 					    curr->gpt_part_info.blksz);
    287 		/* one extra byte for NULL */
    288 		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
    289 		sprintf(partstr, ",size=0x%llx",
    290 			(unsigned long long)curr->gpt_part_info.size *
    291 					    curr->gpt_part_info.blksz);
    292 		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
    293 
    294 		strcat(partitions_list, ",uuid=");
    295 		strncat(partitions_list, curr->gpt_part_info.uuid,
    296 			UUID_STR_LEN + 1);
    297 		strcat(partitions_list, ";");
    298 	}
    299 	return 0;
    300 }
    301 
    302 /*
    303  * read partition info into disk_partitions list where
    304  * it can be printed or modified
    305  */
    306 static int get_gpt_info(struct blk_desc *dev_desc)
    307 {
    308 	/* start partition numbering at 1, as U-Boot does */
    309 	int valid_parts = 0, p, ret;
    310 	disk_partition_t info;
    311 	struct disk_part *new_disk_part;
    312 
    313 	/*
    314 	 * Always re-read partition info from device, in case
    315 	 * it has changed
    316 	 */
    317 	INIT_LIST_HEAD(&disk_partitions);
    318 
    319 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
    320 		ret = part_get_info(dev_desc, p, &info);
    321 		if (ret)
    322 			continue;
    323 
    324 		/* Add 1 here because counter is zero-based but p1 is
    325 		   the first partition */
    326 		new_disk_part = allocate_disk_part(&info, valid_parts+1);
    327 		if (IS_ERR(new_disk_part))
    328 			goto out;
    329 
    330 		list_add_tail(&new_disk_part->list, &disk_partitions);
    331 		valid_parts++;
    332 	}
    333 	if (valid_parts == 0) {
    334 		printf("** No valid partitions found **\n");
    335 		goto out;
    336 	}
    337 	return valid_parts;
    338  out:
    339 	if (valid_parts >= 1)
    340 		del_gpt_info();
    341 	return -ENODEV;
    342 }
    343 
    344 /* a wrapper to test get_gpt_info */
    345 static int do_get_gpt_info(struct blk_desc *dev_desc)
    346 {
    347 	int ret;
    348 
    349 	ret = get_gpt_info(dev_desc);
    350 	if (ret > 0) {
    351 		print_gpt_info();
    352 		del_gpt_info();
    353 		return 0;
    354 	}
    355 	return ret;
    356 }
    357 #endif
    358 
    359 /**
    360  * set_gpt_info(): Fill partition information from string
    361  *		function allocates memory, remember to free!
    362  *
    363  * @param dev_desc - pointer block device descriptor
    364  * @param str_part - pointer to string with partition information
    365  * @param str_disk_guid - pointer to pointer to allocated string with disk guid
    366  * @param partitions - pointer to pointer to allocated partitions array
    367  * @param parts_count - number of partitions
    368  *
    369  * @return - zero on success, otherwise error
    370  *
    371  */
    372 static int set_gpt_info(struct blk_desc *dev_desc,
    373 			const char *str_part,
    374 			char **str_disk_guid,
    375 			disk_partition_t **partitions,
    376 			u8 *parts_count)
    377 {
    378 	char *tok, *str, *s;
    379 	int i;
    380 	char *val, *p;
    381 	int p_count;
    382 	disk_partition_t *parts;
    383 	int errno = 0;
    384 	uint64_t size_ll, start_ll;
    385 	lbaint_t offset = 0;
    386 	int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
    387 
    388 	debug("%s:  lba num: 0x%x %d\n", __func__,
    389 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
    390 
    391 	if (str_part == NULL)
    392 		return -1;
    393 
    394 	str = strdup(str_part);
    395 	if (str == NULL)
    396 		return -ENOMEM;
    397 
    398 	/* extract disk guid */
    399 	s = str;
    400 	val = extract_val(str, "uuid_disk");
    401 	if (!val) {
    402 #ifdef CONFIG_RANDOM_UUID
    403 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
    404 		if (*str_disk_guid == NULL)
    405 			return -ENOMEM;
    406 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
    407 #else
    408 		free(str);
    409 		return -2;
    410 #endif
    411 	} else {
    412 		val = strsep(&val, ";");
    413 		if (extract_env(val, &p))
    414 			p = val;
    415 		*str_disk_guid = strdup(p);
    416 		free(val);
    417 		/* Move s to first partition */
    418 		strsep(&s, ";");
    419 	}
    420 	if (s == NULL) {
    421 		printf("Error: is the partitions string NULL-terminated?\n");
    422 		return -EINVAL;
    423 	}
    424 	if (strnlen(s, max_str_part) == 0)
    425 		return -3;
    426 
    427 	i = strnlen(s, max_str_part) - 1;
    428 	if (s[i] == ';')
    429 		s[i] = '\0';
    430 
    431 	/* calculate expected number of partitions */
    432 	p_count = 1;
    433 	p = s;
    434 	while (*p) {
    435 		if (*p++ == ';')
    436 			p_count++;
    437 	}
    438 
    439 	/* allocate memory for partitions */
    440 	parts = calloc(sizeof(disk_partition_t), p_count);
    441 	if (parts == NULL)
    442 		return -ENOMEM;
    443 
    444 	/* retrieve partitions data from string */
    445 	for (i = 0; i < p_count; i++) {
    446 		tok = strsep(&s, ";");
    447 
    448 		if (tok == NULL)
    449 			break;
    450 
    451 		/* uuid */
    452 		val = extract_val(tok, "uuid");
    453 		if (!val) {
    454 			/* 'uuid' is optional if random uuid's are enabled */
    455 #ifdef CONFIG_RANDOM_UUID
    456 			gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
    457 #else
    458 			errno = -4;
    459 			goto err;
    460 #endif
    461 		} else {
    462 			if (extract_env(val, &p))
    463 				p = val;
    464 			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
    465 				printf("Wrong uuid format for partition %d\n", i);
    466 				errno = -4;
    467 				goto err;
    468 			}
    469 			strncpy((char *)parts[i].uuid, p, max_str_part);
    470 			free(val);
    471 		}
    472 #ifdef CONFIG_PARTITION_TYPE_GUID
    473 		/* guid */
    474 		val = extract_val(tok, "type");
    475 		if (val) {
    476 			/* 'type' is optional */
    477 			if (extract_env(val, &p))
    478 				p = val;
    479 			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
    480 				printf("Wrong type guid format for partition %d\n",
    481 				       i);
    482 				errno = -4;
    483 				goto err;
    484 			}
    485 			strncpy((char *)parts[i].type_guid, p, max_str_part);
    486 			free(val);
    487 		}
    488 #endif
    489 		/* name */
    490 		val = extract_val(tok, "name");
    491 		if (!val) { /* name is mandatory */
    492 			errno = -4;
    493 			goto err;
    494 		}
    495 		if (extract_env(val, &p))
    496 			p = val;
    497 		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
    498 			errno = -4;
    499 			goto err;
    500 		}
    501 		strncpy((char *)parts[i].name, p, max_str_part);
    502 		free(val);
    503 
    504 		/* size */
    505 		val = extract_val(tok, "size");
    506 		if (!val) { /* 'size' is mandatory */
    507 			errno = -4;
    508 			goto err;
    509 		}
    510 		if (extract_env(val, &p))
    511 			p = val;
    512 		if ((strcmp(p, "-") == 0)) {
    513 			/* Let part efi module to auto extend the size */
    514 			parts[i].size = 0;
    515 		} else {
    516 			size_ll = ustrtoull(p, &p, 0);
    517 			parts[i].size = lldiv(size_ll, dev_desc->blksz);
    518 		}
    519 
    520 		free(val);
    521 
    522 		/* start address */
    523 		val = extract_val(tok, "start");
    524 		if (val) { /* start address is optional */
    525 			if (extract_env(val, &p))
    526 				p = val;
    527 			start_ll = ustrtoull(p, &p, 0);
    528 			parts[i].start = lldiv(start_ll, dev_desc->blksz);
    529 			free(val);
    530 		}
    531 
    532 		offset += parts[i].size + parts[i].start;
    533 
    534 		/* bootable */
    535 		if (found_key(tok, "bootable"))
    536 			parts[i].bootable = 1;
    537 	}
    538 
    539 	*parts_count = p_count;
    540 	*partitions = parts;
    541 	free(str);
    542 
    543 	return 0;
    544 err:
    545 	free(str);
    546 	free(*str_disk_guid);
    547 	free(parts);
    548 
    549 	return errno;
    550 }
    551 
    552 static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part)
    553 {
    554 	int ret;
    555 	char *str_disk_guid;
    556 	u8 part_count = 0;
    557 	disk_partition_t *partitions = NULL;
    558 
    559 	/* fill partitions */
    560 	ret = set_gpt_info(blk_dev_desc, str_part,
    561 			&str_disk_guid, &partitions, &part_count);
    562 	if (ret) {
    563 		if (ret == -1)
    564 			printf("No partition list provided\n");
    565 		if (ret == -2)
    566 			printf("Missing disk guid\n");
    567 		if ((ret == -3) || (ret == -4))
    568 			printf("Partition list incomplete\n");
    569 		return -1;
    570 	}
    571 
    572 	/* save partitions layout to disk */
    573 	ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
    574 	free(str_disk_guid);
    575 	free(partitions);
    576 
    577 	return ret;
    578 }
    579 
    580 static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
    581 {
    582 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
    583 				     blk_dev_desc->blksz);
    584 	disk_partition_t *partitions = NULL;
    585 	gpt_entry *gpt_pte = NULL;
    586 	char *str_disk_guid;
    587 	u8 part_count = 0;
    588 	int ret = 0;
    589 
    590 	/* fill partitions */
    591 	ret = set_gpt_info(blk_dev_desc, str_part,
    592 			&str_disk_guid, &partitions, &part_count);
    593 	if (ret) {
    594 		if (ret == -1) {
    595 			printf("No partition list provided - only basic check\n");
    596 			ret = gpt_verify_headers(blk_dev_desc, gpt_head,
    597 						 &gpt_pte);
    598 			goto out;
    599 		}
    600 		if (ret == -2)
    601 			printf("Missing disk guid\n");
    602 		if ((ret == -3) || (ret == -4))
    603 			printf("Partition list incomplete\n");
    604 		return -1;
    605 	}
    606 
    607 	/* Check partition layout with provided pattern */
    608 	ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count,
    609 				    gpt_head, &gpt_pte);
    610 	free(str_disk_guid);
    611 	free(partitions);
    612  out:
    613 	free(gpt_pte);
    614 	return ret;
    615 }
    616 
    617 static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
    618 {
    619 	int ret;
    620 	char disk_guid[UUID_STR_LEN + 1];
    621 
    622 	ret = get_disk_guid(dev_desc, disk_guid);
    623 	if (ret < 0)
    624 		return CMD_RET_FAILURE;
    625 
    626 	if (namestr)
    627 		env_set(namestr, disk_guid);
    628 	else
    629 		printf("%s\n", disk_guid);
    630 
    631 	return ret;
    632 }
    633 
    634 #ifdef CONFIG_CMD_GPT_RENAME
    635 /*
    636  * There are 3 malloc() calls in set_gpt_info() and there is no info about which
    637  * failed.
    638  */
    639 static void set_gpt_cleanup(char **str_disk_guid,
    640 			    disk_partition_t **partitions)
    641 {
    642 #ifdef CONFIG_RANDOM_UUID
    643 	if (str_disk_guid)
    644 		free(str_disk_guid);
    645 #endif
    646 	if (partitions)
    647 		free(partitions);
    648 }
    649 
    650 static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
    651 			       char *name1, char *name2)
    652 {
    653 	struct list_head *pos;
    654 	struct disk_part *curr;
    655 	disk_partition_t *new_partitions = NULL;
    656 	char disk_guid[UUID_STR_LEN + 1];
    657 	char *partitions_list, *str_disk_guid;
    658 	u8 part_count = 0;
    659 	int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
    660 
    661 	if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
    662 	    (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
    663 		return -EINVAL;
    664 
    665 	ret = get_disk_guid(dev_desc, disk_guid);
    666 	if (ret < 0)
    667 		return ret;
    668 	/*
    669 	 * Allocates disk_partitions, requiring matching call to del_gpt_info()
    670 	 * if successful.
    671 	 */
    672 	numparts = get_gpt_info(dev_desc);
    673 	if (numparts <=  0)
    674 		return numparts ? numparts : -ENODEV;
    675 
    676 	partlistlen = calc_parts_list_len(numparts);
    677 	partitions_list = malloc(partlistlen);
    678 	if (!partitions_list) {
    679 		del_gpt_info();
    680 		return -ENOMEM;
    681 	}
    682 	memset(partitions_list, '\0', partlistlen);
    683 
    684 	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
    685 	if (ret < 0) {
    686 		free(partitions_list);
    687 		return ret;
    688 	}
    689 	/*
    690 	 * Uncomment the following line to print a string that 'gpt write'
    691 	 * or 'gpt verify' will accept as input.
    692 	 */
    693 	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
    694 	      (unsigned)strlen(partitions_list));
    695 
    696 	/* set_gpt_info allocates new_partitions and str_disk_guid */
    697 	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
    698 			   &new_partitions, &part_count);
    699 	if (ret < 0) {
    700 		del_gpt_info();
    701 		free(partitions_list);
    702 		if (ret == -ENOMEM)
    703 			set_gpt_cleanup(&str_disk_guid, &new_partitions);
    704 		else
    705 			goto out;
    706 	}
    707 
    708 	if (!strcmp(subcomm, "swap")) {
    709 		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
    710 			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
    711 			ret = -EINVAL;
    712 			goto out;
    713 		}
    714 		list_for_each(pos, &disk_partitions) {
    715 			curr = list_entry(pos, struct disk_part, list);
    716 			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
    717 				strcpy((char *)curr->gpt_part_info.name, name2);
    718 				ctr1++;
    719 			} else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
    720 				strcpy((char *)curr->gpt_part_info.name, name1);
    721 				ctr2++;
    722 			}
    723 		}
    724 		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
    725 			printf("Cannot swap partition names except in pairs.\n");
    726 			ret = -EINVAL;
    727 			goto out;
    728 		}
    729 	} else { /* rename */
    730 		if (strlen(name2) > PART_NAME_LEN) {
    731 			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
    732 			ret = -EINVAL;
    733 			goto out;
    734 		}
    735 		partnum = (int)simple_strtol(name1, NULL, 10);
    736 		if ((partnum < 0) || (partnum > numparts)) {
    737 			printf("Illegal partition number %s\n", name1);
    738 			ret = -EINVAL;
    739 			goto out;
    740 		}
    741 		ret = part_get_info(dev_desc, partnum, new_partitions);
    742 		if (ret < 0)
    743 			goto out;
    744 
    745 		/* U-Boot partition numbering starts at 1 */
    746 		list_for_each(pos, &disk_partitions) {
    747 			curr = list_entry(pos, struct disk_part, list);
    748 			if (i == partnum) {
    749 				strcpy((char *)curr->gpt_part_info.name, name2);
    750 				break;
    751 			}
    752 			i++;
    753 		}
    754 	}
    755 
    756 	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
    757 	if (ret < 0)
    758 		goto out;
    759 	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
    760 	      (unsigned)strlen(partitions_list));
    761 
    762 	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
    763 			   &new_partitions, &part_count);
    764 	/*
    765 	 * Even though valid pointers are here passed into set_gpt_info(),
    766 	 * it mallocs again, and there's no way to tell which failed.
    767 	 */
    768 	if (ret < 0) {
    769 		del_gpt_info();
    770 		free(partitions_list);
    771 		if (ret == -ENOMEM)
    772 			set_gpt_cleanup(&str_disk_guid, &new_partitions);
    773 		else
    774 			goto out;
    775 	}
    776 
    777 	debug("Writing new partition table\n");
    778 	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
    779 	if (ret < 0) {
    780 		printf("Writing new partition table failed\n");
    781 		goto out;
    782 	}
    783 
    784 	debug("Reading back new partition table\n");
    785 	/*
    786 	 * Empty the existing disk_partitions list, as otherwise the memory in
    787 	 * the original list is unreachable.
    788 	 */
    789 	del_gpt_info();
    790 	numparts = get_gpt_info(dev_desc);
    791 	if (numparts <=  0) {
    792 		ret = numparts ? numparts : -ENODEV;
    793 		goto out;
    794 	}
    795 	printf("new partition table with %d partitions is:\n", numparts);
    796 	print_gpt_info();
    797 	del_gpt_info();
    798  out:
    799 	free(new_partitions);
    800 	free(str_disk_guid);
    801 	free(partitions_list);
    802 	return ret;
    803 }
    804 #endif
    805 
    806 /**
    807  * do_gpt(): Perform GPT operations
    808  *
    809  * @param cmdtp - command name
    810  * @param flag
    811  * @param argc
    812  * @param argv
    813  *
    814  * @return zero on success; otherwise error
    815  */
    816 static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
    817 {
    818 	int ret = CMD_RET_SUCCESS;
    819 	int dev = 0;
    820 	char *ep;
    821 	struct blk_desc *blk_dev_desc = NULL;
    822 
    823 #ifndef CONFIG_CMD_GPT_RENAME
    824 	if (argc < 4 || argc > 5)
    825 #else
    826 	if (argc < 4 || argc > 6)
    827 #endif
    828 		return CMD_RET_USAGE;
    829 
    830 	dev = (int)simple_strtoul(argv[3], &ep, 10);
    831 	if (!ep || ep[0] != '\0') {
    832 		printf("'%s' is not a number\n", argv[3]);
    833 		return CMD_RET_USAGE;
    834 	}
    835 	blk_dev_desc = blk_get_dev(argv[2], dev);
    836 	if (!blk_dev_desc) {
    837 		printf("%s: %s dev %d NOT available\n",
    838 		       __func__, argv[2], dev);
    839 		return CMD_RET_FAILURE;
    840 	}
    841 
    842 	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
    843 		printf("Writing GPT: ");
    844 		ret = gpt_default(blk_dev_desc, argv[4]);
    845 	} else if ((strcmp(argv[1], "verify") == 0)) {
    846 		ret = gpt_verify(blk_dev_desc, argv[4]);
    847 		printf("Verify GPT: ");
    848 	} else if (strcmp(argv[1], "guid") == 0) {
    849 		ret = do_disk_guid(blk_dev_desc, argv[4]);
    850 #ifdef CONFIG_CMD_GPT_RENAME
    851 	} else if (strcmp(argv[1], "read") == 0) {
    852 		ret = do_get_gpt_info(blk_dev_desc);
    853 	} else if ((strcmp(argv[1], "swap") == 0) ||
    854 		   (strcmp(argv[1], "rename") == 0)) {
    855 		ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
    856 #endif
    857 	} else {
    858 		return CMD_RET_USAGE;
    859 	}
    860 
    861 	if (ret) {
    862 		printf("error!\n");
    863 		return CMD_RET_FAILURE;
    864 	}
    865 
    866 	printf("success!\n");
    867 	return CMD_RET_SUCCESS;
    868 }
    869 
    870 U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
    871 	"GUID Partition Table",
    872 	"<command> <interface> <dev> <partitions_list>\n"
    873 	" - GUID partition table restoration and validity check\n"
    874 	" Restore or verify GPT information on a device connected\n"
    875 	" to interface\n"
    876 	" Example usage:\n"
    877 	" gpt write mmc 0 $partitions\n"
    878 	" gpt verify mmc 0 $partitions\n"
    879 	" read <interface> <dev>\n"
    880 	"    - read GPT into a data structure for manipulation\n"
    881 	" guid <interface> <dev>\n"
    882 	"    - print disk GUID\n"
    883 	" guid <interface> <dev> <varname>\n"
    884 	"    - set environment variable to disk GUID\n"
    885 	" Example usage:\n"
    886 	" gpt guid mmc 0\n"
    887 	" gpt guid mmc 0 varname\n"
    888 #ifdef CONFIG_CMD_GPT_RENAME
    889 	"gpt partition renaming commands:\n"
    890 	"gpt swap <interface> <dev> <name1> <name2>\n"
    891 	"    - change all partitions named name1 to name2\n"
    892 	"      and vice-versa\n"
    893 	"gpt rename <interface> <dev> <part> <name>\n"
    894 	"    - rename the specified partition\n"
    895 	" Example usage:\n"
    896 	" gpt swap mmc 0 foo bar\n"
    897 	" gpt rename mmc 0 3 foo\n"
    898 #endif
    899 );
    900