12e192b24SSimon Glass /* 22e192b24SSimon Glass * cmd_gpt.c -- GPT (GUID Partition Table) handling command 32e192b24SSimon Glass * 42e192b24SSimon Glass * Copyright (C) 2015 52e192b24SSimon Glass * Lukasz Majewski <l.majewski@majess.pl> 62e192b24SSimon Glass * 72e192b24SSimon Glass * Copyright (C) 2012 Samsung Electronics 82e192b24SSimon Glass * author: Lukasz Majewski <l.majewski@samsung.com> 92e192b24SSimon Glass * author: Piotr Wilczek <p.wilczek@samsung.com> 102e192b24SSimon Glass * 112e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 122e192b24SSimon Glass */ 132e192b24SSimon Glass 142e192b24SSimon Glass #include <common.h> 152e192b24SSimon Glass #include <malloc.h> 162e192b24SSimon Glass #include <command.h> 172e192b24SSimon Glass #include <part_efi.h> 182e192b24SSimon Glass #include <exports.h> 192e192b24SSimon Glass #include <linux/ctype.h> 202e192b24SSimon Glass #include <div64.h> 212e192b24SSimon Glass #include <memalign.h> 2209a49930SAlison Chaiken #include <linux/compat.h> 23203f9b48SAlison Chaiken #include <linux/sizes.h> 24203f9b48SAlison Chaiken #include <stdlib.h> 2509a49930SAlison Chaiken 2609a49930SAlison Chaiken static LIST_HEAD(disk_partitions); 272e192b24SSimon Glass 282e192b24SSimon Glass /** 292e192b24SSimon Glass * extract_env(): Expand env name from string format '&{env_name}' 302e192b24SSimon Glass * and return pointer to the env (if the env is set) 312e192b24SSimon Glass * 322e192b24SSimon Glass * @param str - pointer to string 332e192b24SSimon Glass * @param env - pointer to pointer to extracted env 342e192b24SSimon Glass * 352e192b24SSimon Glass * @return - zero on successful expand and env is set 362e192b24SSimon Glass */ 372e192b24SSimon Glass static int extract_env(const char *str, char **env) 382e192b24SSimon Glass { 392e192b24SSimon Glass int ret = -1; 402e192b24SSimon Glass char *e, *s; 412e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID 422e192b24SSimon Glass char uuid_str[UUID_STR_LEN + 1]; 432e192b24SSimon Glass #endif 442e192b24SSimon Glass 452e192b24SSimon Glass if (!str || strlen(str) < 4) 462e192b24SSimon Glass return -1; 472e192b24SSimon Glass 482e192b24SSimon Glass if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}'))) 492e192b24SSimon Glass return -1; 502e192b24SSimon Glass 512e192b24SSimon Glass s = strdup(str); 522e192b24SSimon Glass if (s == NULL) 532e192b24SSimon Glass return -1; 542e192b24SSimon Glass 552e192b24SSimon Glass memset(s + strlen(s) - 1, '\0', 1); 562e192b24SSimon Glass memmove(s, s + 2, strlen(s) - 1); 572e192b24SSimon Glass 5800caae6dSSimon Glass e = env_get(s); 592e192b24SSimon Glass if (e == NULL) { 602e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID 612e192b24SSimon Glass debug("%s unset. ", str); 629da52f8fSVincent Tinelli gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID); 63382bee57SSimon Glass env_set(s, uuid_str); 642e192b24SSimon Glass 6500caae6dSSimon Glass e = env_get(s); 662e192b24SSimon Glass if (e) { 672e192b24SSimon Glass debug("Set to random.\n"); 682e192b24SSimon Glass ret = 0; 692e192b24SSimon Glass } else { 702e192b24SSimon Glass debug("Can't get random UUID.\n"); 712e192b24SSimon Glass } 722e192b24SSimon Glass #else 732e192b24SSimon Glass debug("%s unset.\n", str); 742e192b24SSimon Glass #endif 752e192b24SSimon Glass } else { 762e192b24SSimon Glass debug("%s get from environment.\n", str); 772e192b24SSimon Glass ret = 0; 782e192b24SSimon Glass } 792e192b24SSimon Glass 802e192b24SSimon Glass *env = e; 812e192b24SSimon Glass free(s); 822e192b24SSimon Glass 832e192b24SSimon Glass return ret; 842e192b24SSimon Glass } 852e192b24SSimon Glass 862e192b24SSimon Glass /** 872e192b24SSimon Glass * extract_val(): Extract value from a key=value pair list (comma separated). 882e192b24SSimon Glass * Only value for the given key is returend. 892e192b24SSimon Glass * Function allocates memory for the value, remember to free! 902e192b24SSimon Glass * 912e192b24SSimon Glass * @param str - pointer to string with key=values pairs 922e192b24SSimon Glass * @param key - pointer to the key to search for 932e192b24SSimon Glass * 942e192b24SSimon Glass * @return - pointer to allocated string with the value 952e192b24SSimon Glass */ 962e192b24SSimon Glass static char *extract_val(const char *str, const char *key) 972e192b24SSimon Glass { 982e192b24SSimon Glass char *v, *k; 992e192b24SSimon Glass char *s, *strcopy; 1002e192b24SSimon Glass char *new = NULL; 1012e192b24SSimon Glass 1022e192b24SSimon Glass strcopy = strdup(str); 1032e192b24SSimon Glass if (strcopy == NULL) 1042e192b24SSimon Glass return NULL; 1052e192b24SSimon Glass 1062e192b24SSimon Glass s = strcopy; 1072e192b24SSimon Glass while (s) { 1082e192b24SSimon Glass v = strsep(&s, ","); 1092e192b24SSimon Glass if (!v) 1102e192b24SSimon Glass break; 1112e192b24SSimon Glass k = strsep(&v, "="); 1122e192b24SSimon Glass if (!k) 1132e192b24SSimon Glass break; 1142e192b24SSimon Glass if (strcmp(k, key) == 0) { 1152e192b24SSimon Glass new = strdup(v); 1162e192b24SSimon Glass break; 1172e192b24SSimon Glass } 1182e192b24SSimon Glass } 1192e192b24SSimon Glass 1202e192b24SSimon Glass free(strcopy); 1212e192b24SSimon Glass 1222e192b24SSimon Glass return new; 1232e192b24SSimon Glass } 1242e192b24SSimon Glass 1252e192b24SSimon Glass /** 1262e192b24SSimon Glass * found_key(): Found key without value in parameter list (comma separated). 1272e192b24SSimon Glass * 1282e192b24SSimon Glass * @param str - pointer to string with key 1292e192b24SSimon Glass * @param key - pointer to the key to search for 1302e192b24SSimon Glass * 1312e192b24SSimon Glass * @return - true on found key 1322e192b24SSimon Glass */ 1332e192b24SSimon Glass static bool found_key(const char *str, const char *key) 1342e192b24SSimon Glass { 1352e192b24SSimon Glass char *k; 1362e192b24SSimon Glass char *s, *strcopy; 1372e192b24SSimon Glass bool result = false; 1382e192b24SSimon Glass 1392e192b24SSimon Glass strcopy = strdup(str); 1402e192b24SSimon Glass if (!strcopy) 1412e192b24SSimon Glass return NULL; 1422e192b24SSimon Glass 1432e192b24SSimon Glass s = strcopy; 1442e192b24SSimon Glass while (s) { 1452e192b24SSimon Glass k = strsep(&s, ","); 1462e192b24SSimon Glass if (!k) 1472e192b24SSimon Glass break; 1482e192b24SSimon Glass if (strcmp(k, key) == 0) { 1492e192b24SSimon Glass result = true; 1502e192b24SSimon Glass break; 1512e192b24SSimon Glass } 1522e192b24SSimon Glass } 1532e192b24SSimon Glass 1542e192b24SSimon Glass free(strcopy); 1552e192b24SSimon Glass 1562e192b24SSimon Glass return result; 1572e192b24SSimon Glass } 1582e192b24SSimon Glass 1592fcaa413SAlison Chaiken static int calc_parts_list_len(int numparts) 1602fcaa413SAlison Chaiken { 1612fcaa413SAlison Chaiken int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk="); 1622fcaa413SAlison Chaiken /* for the comma */ 1632fcaa413SAlison Chaiken partlistlen++; 1642fcaa413SAlison Chaiken 1652fcaa413SAlison Chaiken /* per-partition additions; numparts starts at 1, so this should be correct */ 1662fcaa413SAlison Chaiken partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1); 1672fcaa413SAlison Chaiken /* see part.h for definition of struct disk_partition */ 1682fcaa413SAlison Chaiken partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); 1692fcaa413SAlison Chaiken partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); 1702fcaa413SAlison Chaiken partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); 1712fcaa413SAlison Chaiken /* for the terminating null */ 1722fcaa413SAlison Chaiken partlistlen++; 1732fcaa413SAlison Chaiken debug("Length of partitions_list is %d for %d partitions\n", partlistlen, 1742fcaa413SAlison Chaiken numparts); 1752fcaa413SAlison Chaiken return partlistlen; 1762fcaa413SAlison Chaiken } 1772fcaa413SAlison Chaiken 17809a49930SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME 17909a49930SAlison Chaiken static void del_gpt_info(void) 18009a49930SAlison Chaiken { 18109a49930SAlison Chaiken struct list_head *pos = &disk_partitions; 18209a49930SAlison Chaiken struct disk_part *curr; 18309a49930SAlison Chaiken while (!list_empty(pos)) { 18409a49930SAlison Chaiken curr = list_entry(pos->next, struct disk_part, list); 18509a49930SAlison Chaiken list_del(pos->next); 18609a49930SAlison Chaiken free(curr); 18709a49930SAlison Chaiken } 18809a49930SAlison Chaiken } 18909a49930SAlison Chaiken 19009a49930SAlison Chaiken static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum) 19109a49930SAlison Chaiken { 19209a49930SAlison Chaiken struct disk_part *newpart; 19331526294SHeinrich Schuchardt newpart = calloc(1, sizeof(struct disk_part)); 19409a49930SAlison Chaiken if (!newpart) 19509a49930SAlison Chaiken return ERR_PTR(-ENOMEM); 19609a49930SAlison Chaiken 19709a49930SAlison Chaiken newpart->gpt_part_info.start = info->start; 19809a49930SAlison Chaiken newpart->gpt_part_info.size = info->size; 19909a49930SAlison Chaiken newpart->gpt_part_info.blksz = info->blksz; 20009a49930SAlison Chaiken strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, 20109a49930SAlison Chaiken PART_NAME_LEN); 20209a49930SAlison Chaiken newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0'; 20309a49930SAlison Chaiken strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, 20409a49930SAlison Chaiken PART_TYPE_LEN); 20509a49930SAlison Chaiken newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; 20609a49930SAlison Chaiken newpart->gpt_part_info.bootable = info->bootable; 20709a49930SAlison Chaiken #ifdef CONFIG_PARTITION_UUIDS 20809a49930SAlison Chaiken strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, 20909a49930SAlison Chaiken UUID_STR_LEN); 21009a49930SAlison Chaiken /* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */ 21109a49930SAlison Chaiken newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0'; 21209a49930SAlison Chaiken #endif 21309a49930SAlison Chaiken newpart->partnum = partnum; 21409a49930SAlison Chaiken 21509a49930SAlison Chaiken return newpart; 21609a49930SAlison Chaiken } 21709a49930SAlison Chaiken 218203f9b48SAlison Chaiken static void prettyprint_part_size(char *sizestr, lbaint_t partsize, 219203f9b48SAlison Chaiken lbaint_t blksize) 220203f9b48SAlison Chaiken { 221203f9b48SAlison Chaiken unsigned long long partbytes, partmegabytes; 222203f9b48SAlison Chaiken 223203f9b48SAlison Chaiken partbytes = partsize * blksize; 224203f9b48SAlison Chaiken partmegabytes = lldiv(partbytes, SZ_1M); 225203f9b48SAlison Chaiken snprintf(sizestr, 16, "%lluMiB", partmegabytes); 226203f9b48SAlison Chaiken } 227203f9b48SAlison Chaiken 22809a49930SAlison Chaiken static void print_gpt_info(void) 22909a49930SAlison Chaiken { 23009a49930SAlison Chaiken struct list_head *pos; 23109a49930SAlison Chaiken struct disk_part *curr; 232203f9b48SAlison Chaiken char partstartstr[16]; 233203f9b48SAlison Chaiken char partsizestr[16]; 23409a49930SAlison Chaiken 23509a49930SAlison Chaiken list_for_each(pos, &disk_partitions) { 23609a49930SAlison Chaiken curr = list_entry(pos, struct disk_part, list); 237203f9b48SAlison Chaiken prettyprint_part_size(partstartstr, curr->gpt_part_info.start, 238203f9b48SAlison Chaiken curr->gpt_part_info.blksz); 239203f9b48SAlison Chaiken prettyprint_part_size(partsizestr, curr->gpt_part_info.size, 240203f9b48SAlison Chaiken curr->gpt_part_info.blksz); 241203f9b48SAlison Chaiken 24209a49930SAlison Chaiken printf("Partition %d:\n", curr->partnum); 243203f9b48SAlison Chaiken printf("Start %s, size %s\n", partstartstr, partsizestr); 24409a49930SAlison Chaiken printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz, 24509a49930SAlison Chaiken curr->gpt_part_info.name); 24609a49930SAlison Chaiken printf("Type %s, bootable %d\n", curr->gpt_part_info.type, 24709a49930SAlison Chaiken curr->gpt_part_info.bootable); 24809a49930SAlison Chaiken #ifdef CONFIG_PARTITION_UUIDS 24909a49930SAlison Chaiken printf("UUID %s\n", curr->gpt_part_info.uuid); 25009a49930SAlison Chaiken #endif 25109a49930SAlison Chaiken printf("\n"); 25209a49930SAlison Chaiken } 25309a49930SAlison Chaiken } 25409a49930SAlison Chaiken 255203f9b48SAlison Chaiken /* 256203f9b48SAlison Chaiken * create the string that upstream 'gpt write' command will accept as an 257203f9b48SAlison Chaiken * argument 258203f9b48SAlison Chaiken * 259203f9b48SAlison Chaiken * From doc/README.gpt, Format of partitions layout: 260203f9b48SAlison Chaiken * "uuid_disk=...;name=u-boot,size=60MiB,uuid=...; 261203f9b48SAlison Chaiken * name=kernel,size=60MiB,uuid=...;" 262203f9b48SAlison Chaiken * The fields 'name' and 'size' are mandatory for every partition. 263203f9b48SAlison Chaiken * The field 'start' is optional. The fields 'uuid' and 'uuid_disk' 264203f9b48SAlison Chaiken * are optional if CONFIG_RANDOM_UUID is enabled. 265203f9b48SAlison Chaiken */ 266203f9b48SAlison Chaiken static int create_gpt_partitions_list(int numparts, const char *guid, 267203f9b48SAlison Chaiken char *partitions_list) 268203f9b48SAlison Chaiken { 269203f9b48SAlison Chaiken struct list_head *pos; 270203f9b48SAlison Chaiken struct disk_part *curr; 271203f9b48SAlison Chaiken char partstr[PART_NAME_LEN + 1]; 272203f9b48SAlison Chaiken 273203f9b48SAlison Chaiken if (!partitions_list) 274203f9b48SAlison Chaiken return -EINVAL; 275203f9b48SAlison Chaiken 276203f9b48SAlison Chaiken strcpy(partitions_list, "uuid_disk="); 277203f9b48SAlison Chaiken strncat(partitions_list, guid, UUID_STR_LEN + 1); 278203f9b48SAlison Chaiken strcat(partitions_list, ";"); 279203f9b48SAlison Chaiken 280203f9b48SAlison Chaiken list_for_each(pos, &disk_partitions) { 281203f9b48SAlison Chaiken curr = list_entry(pos, struct disk_part, list); 282203f9b48SAlison Chaiken strcat(partitions_list, "name="); 283203f9b48SAlison Chaiken strncat(partitions_list, (const char *)curr->gpt_part_info.name, 284203f9b48SAlison Chaiken PART_NAME_LEN + 1); 285203f9b48SAlison Chaiken strcat(partitions_list, ",start="); 286203f9b48SAlison Chaiken prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start, 287203f9b48SAlison Chaiken (unsigned long) curr->gpt_part_info.blksz); 288203f9b48SAlison Chaiken /* one extra byte for NULL */ 289203f9b48SAlison Chaiken strncat(partitions_list, partstr, PART_NAME_LEN + 1); 290203f9b48SAlison Chaiken strcat(partitions_list, ",size="); 291203f9b48SAlison Chaiken prettyprint_part_size(partstr, curr->gpt_part_info.size, 292203f9b48SAlison Chaiken curr->gpt_part_info.blksz); 293203f9b48SAlison Chaiken strncat(partitions_list, partstr, PART_NAME_LEN + 1); 294203f9b48SAlison Chaiken 295203f9b48SAlison Chaiken strcat(partitions_list, ",uuid="); 296203f9b48SAlison Chaiken strncat(partitions_list, curr->gpt_part_info.uuid, 297203f9b48SAlison Chaiken UUID_STR_LEN + 1); 298203f9b48SAlison Chaiken strcat(partitions_list, ";"); 299203f9b48SAlison Chaiken } 300203f9b48SAlison Chaiken return 0; 301203f9b48SAlison Chaiken } 302203f9b48SAlison Chaiken 30309a49930SAlison Chaiken /* 30409a49930SAlison Chaiken * read partition info into disk_partitions list where 30509a49930SAlison Chaiken * it can be printed or modified 30609a49930SAlison Chaiken */ 30709a49930SAlison Chaiken static int get_gpt_info(struct blk_desc *dev_desc) 30809a49930SAlison Chaiken { 30909a49930SAlison Chaiken /* start partition numbering at 1, as U-Boot does */ 31009a49930SAlison Chaiken int valid_parts = 0, p, ret; 31109a49930SAlison Chaiken disk_partition_t info; 31209a49930SAlison Chaiken struct disk_part *new_disk_part; 31309a49930SAlison Chaiken 314203f9b48SAlison Chaiken /* 315203f9b48SAlison Chaiken * Always re-read partition info from device, in case 316203f9b48SAlison Chaiken * it has changed 317203f9b48SAlison Chaiken */ 31809a49930SAlison Chaiken INIT_LIST_HEAD(&disk_partitions); 31909a49930SAlison Chaiken 32009a49930SAlison Chaiken for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 32109a49930SAlison Chaiken ret = part_get_info(dev_desc, p, &info); 32209a49930SAlison Chaiken if (ret) 32309a49930SAlison Chaiken continue; 32409a49930SAlison Chaiken 32509a49930SAlison Chaiken /* Add 1 here because counter is zero-based but p1 is 32609a49930SAlison Chaiken the first partition */ 32709a49930SAlison Chaiken new_disk_part = allocate_disk_part(&info, valid_parts+1); 32809a49930SAlison Chaiken if (IS_ERR(new_disk_part)) 32909a49930SAlison Chaiken goto out; 33009a49930SAlison Chaiken 33109a49930SAlison Chaiken list_add_tail(&new_disk_part->list, &disk_partitions); 33209a49930SAlison Chaiken valid_parts++; 33309a49930SAlison Chaiken } 33409a49930SAlison Chaiken if (valid_parts == 0) { 33509a49930SAlison Chaiken printf("** No valid partitions found **\n"); 33609a49930SAlison Chaiken goto out; 33709a49930SAlison Chaiken } 33809a49930SAlison Chaiken return valid_parts; 33909a49930SAlison Chaiken out: 34009a49930SAlison Chaiken if (valid_parts >= 1) 34109a49930SAlison Chaiken del_gpt_info(); 34209a49930SAlison Chaiken return -ENODEV; 34309a49930SAlison Chaiken } 34409a49930SAlison Chaiken 34509a49930SAlison Chaiken /* a wrapper to test get_gpt_info */ 34609a49930SAlison Chaiken static int do_get_gpt_info(struct blk_desc *dev_desc) 34709a49930SAlison Chaiken { 34809a49930SAlison Chaiken int ret; 34909a49930SAlison Chaiken 35009a49930SAlison Chaiken ret = get_gpt_info(dev_desc); 35109a49930SAlison Chaiken if (ret > 0) { 35209a49930SAlison Chaiken print_gpt_info(); 35309a49930SAlison Chaiken del_gpt_info(); 35409a49930SAlison Chaiken return 0; 35509a49930SAlison Chaiken } 35609a49930SAlison Chaiken return ret; 35709a49930SAlison Chaiken } 35809a49930SAlison Chaiken #endif 35909a49930SAlison Chaiken 3602e192b24SSimon Glass /** 3612e192b24SSimon Glass * set_gpt_info(): Fill partition information from string 3622e192b24SSimon Glass * function allocates memory, remember to free! 3632e192b24SSimon Glass * 3642e192b24SSimon Glass * @param dev_desc - pointer block device descriptor 3652e192b24SSimon Glass * @param str_part - pointer to string with partition information 3662e192b24SSimon Glass * @param str_disk_guid - pointer to pointer to allocated string with disk guid 3672e192b24SSimon Glass * @param partitions - pointer to pointer to allocated partitions array 3682e192b24SSimon Glass * @param parts_count - number of partitions 3692e192b24SSimon Glass * 3702e192b24SSimon Glass * @return - zero on success, otherwise error 3712e192b24SSimon Glass * 3722e192b24SSimon Glass */ 3734101f687SSimon Glass static int set_gpt_info(struct blk_desc *dev_desc, 3742e192b24SSimon Glass const char *str_part, 3752e192b24SSimon Glass char **str_disk_guid, 3762e192b24SSimon Glass disk_partition_t **partitions, 3772e192b24SSimon Glass u8 *parts_count) 3782e192b24SSimon Glass { 3792e192b24SSimon Glass char *tok, *str, *s; 3802e192b24SSimon Glass int i; 3812e192b24SSimon Glass char *val, *p; 3822e192b24SSimon Glass int p_count; 3832e192b24SSimon Glass disk_partition_t *parts; 3842e192b24SSimon Glass int errno = 0; 3852e192b24SSimon Glass uint64_t size_ll, start_ll; 38666636235SMichael Trimarchi lbaint_t offset = 0; 3872fcaa413SAlison Chaiken int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS); 3882e192b24SSimon Glass 3892e192b24SSimon Glass debug("%s: lba num: 0x%x %d\n", __func__, 3902e192b24SSimon Glass (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); 3912e192b24SSimon Glass 3922e192b24SSimon Glass if (str_part == NULL) 3932e192b24SSimon Glass return -1; 3942e192b24SSimon Glass 3952e192b24SSimon Glass str = strdup(str_part); 396203f9b48SAlison Chaiken if (str == NULL) 397203f9b48SAlison Chaiken return -ENOMEM; 3982e192b24SSimon Glass 3992e192b24SSimon Glass /* extract disk guid */ 4002e192b24SSimon Glass s = str; 4012e192b24SSimon Glass val = extract_val(str, "uuid_disk"); 4022e192b24SSimon Glass if (!val) { 4032e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID 4042e192b24SSimon Glass *str_disk_guid = malloc(UUID_STR_LEN + 1); 4052fcaa413SAlison Chaiken if (str_disk_guid == NULL) 4062fcaa413SAlison Chaiken return -ENOMEM; 4072e192b24SSimon Glass gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD); 4082e192b24SSimon Glass #else 4092e192b24SSimon Glass free(str); 4102e192b24SSimon Glass return -2; 4112e192b24SSimon Glass #endif 4122e192b24SSimon Glass } else { 4132e192b24SSimon Glass val = strsep(&val, ";"); 4142e192b24SSimon Glass if (extract_env(val, &p)) 4152e192b24SSimon Glass p = val; 4162e192b24SSimon Glass *str_disk_guid = strdup(p); 4172e192b24SSimon Glass free(val); 4182e192b24SSimon Glass /* Move s to first partition */ 4192e192b24SSimon Glass strsep(&s, ";"); 4202e192b24SSimon Glass } 4212fcaa413SAlison Chaiken if (s == NULL) { 4222fcaa413SAlison Chaiken printf("Error: is the partitions string NULL-terminated?\n"); 4232fcaa413SAlison Chaiken return -EINVAL; 4242fcaa413SAlison Chaiken } 4252fcaa413SAlison Chaiken if (strnlen(s, max_str_part) == 0) 4262e192b24SSimon Glass return -3; 4272e192b24SSimon Glass 4282fcaa413SAlison Chaiken i = strnlen(s, max_str_part) - 1; 4292e192b24SSimon Glass if (s[i] == ';') 4302e192b24SSimon Glass s[i] = '\0'; 4312e192b24SSimon Glass 4322e192b24SSimon Glass /* calculate expected number of partitions */ 4332e192b24SSimon Glass p_count = 1; 4342e192b24SSimon Glass p = s; 4352e192b24SSimon Glass while (*p) { 4362e192b24SSimon Glass if (*p++ == ';') 4372e192b24SSimon Glass p_count++; 4382e192b24SSimon Glass } 4392e192b24SSimon Glass 4402e192b24SSimon Glass /* allocate memory for partitions */ 4412e192b24SSimon Glass parts = calloc(sizeof(disk_partition_t), p_count); 4422fcaa413SAlison Chaiken if (parts == NULL) 4432fcaa413SAlison Chaiken return -ENOMEM; 4442e192b24SSimon Glass 4452e192b24SSimon Glass /* retrieve partitions data from string */ 4462e192b24SSimon Glass for (i = 0; i < p_count; i++) { 4472e192b24SSimon Glass tok = strsep(&s, ";"); 4482e192b24SSimon Glass 4492e192b24SSimon Glass if (tok == NULL) 4502e192b24SSimon Glass break; 4512e192b24SSimon Glass 4522e192b24SSimon Glass /* uuid */ 4532e192b24SSimon Glass val = extract_val(tok, "uuid"); 4542e192b24SSimon Glass if (!val) { 4552e192b24SSimon Glass /* 'uuid' is optional if random uuid's are enabled */ 4562e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID 4572e192b24SSimon Glass gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD); 4582e192b24SSimon Glass #else 4592e192b24SSimon Glass errno = -4; 4602e192b24SSimon Glass goto err; 4612e192b24SSimon Glass #endif 4622e192b24SSimon Glass } else { 4632e192b24SSimon Glass if (extract_env(val, &p)) 4642e192b24SSimon Glass p = val; 4652fcaa413SAlison Chaiken if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) { 4662e192b24SSimon Glass printf("Wrong uuid format for partition %d\n", i); 4672e192b24SSimon Glass errno = -4; 4682e192b24SSimon Glass goto err; 4692e192b24SSimon Glass } 4702fcaa413SAlison Chaiken strncpy((char *)parts[i].uuid, p, max_str_part); 4712e192b24SSimon Glass free(val); 4722e192b24SSimon Glass } 4732e192b24SSimon Glass #ifdef CONFIG_PARTITION_TYPE_GUID 4742e192b24SSimon Glass /* guid */ 4752e192b24SSimon Glass val = extract_val(tok, "type"); 4762e192b24SSimon Glass if (val) { 4772e192b24SSimon Glass /* 'type' is optional */ 4782e192b24SSimon Glass if (extract_env(val, &p)) 4792e192b24SSimon Glass p = val; 4802fcaa413SAlison Chaiken if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) { 4812e192b24SSimon Glass printf("Wrong type guid format for partition %d\n", 4822e192b24SSimon Glass i); 4832e192b24SSimon Glass errno = -4; 4842e192b24SSimon Glass goto err; 4852e192b24SSimon Glass } 4862fcaa413SAlison Chaiken strncpy((char *)parts[i].type_guid, p, max_str_part); 4872e192b24SSimon Glass free(val); 4882e192b24SSimon Glass } 4892e192b24SSimon Glass #endif 4902e192b24SSimon Glass /* name */ 4912e192b24SSimon Glass val = extract_val(tok, "name"); 4922e192b24SSimon Glass if (!val) { /* name is mandatory */ 4932e192b24SSimon Glass errno = -4; 4942e192b24SSimon Glass goto err; 4952e192b24SSimon Glass } 4962e192b24SSimon Glass if (extract_env(val, &p)) 4972e192b24SSimon Glass p = val; 4982fcaa413SAlison Chaiken if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) { 4992e192b24SSimon Glass errno = -4; 5002e192b24SSimon Glass goto err; 5012e192b24SSimon Glass } 5022fcaa413SAlison Chaiken strncpy((char *)parts[i].name, p, max_str_part); 5032e192b24SSimon Glass free(val); 5042e192b24SSimon Glass 5052e192b24SSimon Glass /* size */ 5062e192b24SSimon Glass val = extract_val(tok, "size"); 5072e192b24SSimon Glass if (!val) { /* 'size' is mandatory */ 5082e192b24SSimon Glass errno = -4; 5092e192b24SSimon Glass goto err; 5102e192b24SSimon Glass } 5112e192b24SSimon Glass if (extract_env(val, &p)) 5122e192b24SSimon Glass p = val; 51366636235SMichael Trimarchi if ((strcmp(p, "-") == 0)) { 514c2fdd345SKever Yang /* Let part efi module to auto extend the size */ 515c2fdd345SKever Yang parts[i].size = 0; 51666636235SMichael Trimarchi } else { 5172e192b24SSimon Glass size_ll = ustrtoull(p, &p, 0); 5182e192b24SSimon Glass parts[i].size = lldiv(size_ll, dev_desc->blksz); 51966636235SMichael Trimarchi } 52066636235SMichael Trimarchi 5212e192b24SSimon Glass free(val); 5222e192b24SSimon Glass 5232e192b24SSimon Glass /* start address */ 5242e192b24SSimon Glass val = extract_val(tok, "start"); 5252e192b24SSimon Glass if (val) { /* start address is optional */ 5262e192b24SSimon Glass if (extract_env(val, &p)) 5272e192b24SSimon Glass p = val; 5282e192b24SSimon Glass start_ll = ustrtoull(p, &p, 0); 5292e192b24SSimon Glass parts[i].start = lldiv(start_ll, dev_desc->blksz); 5302e192b24SSimon Glass free(val); 5312e192b24SSimon Glass } 5322e192b24SSimon Glass 53366636235SMichael Trimarchi offset += parts[i].size + parts[i].start; 53466636235SMichael Trimarchi 5352e192b24SSimon Glass /* bootable */ 5362e192b24SSimon Glass if (found_key(tok, "bootable")) 5372e192b24SSimon Glass parts[i].bootable = 1; 5382e192b24SSimon Glass } 5392e192b24SSimon Glass 5402e192b24SSimon Glass *parts_count = p_count; 5412e192b24SSimon Glass *partitions = parts; 5422e192b24SSimon Glass free(str); 5432e192b24SSimon Glass 5442e192b24SSimon Glass return 0; 5452e192b24SSimon Glass err: 5462e192b24SSimon Glass free(str); 5472e192b24SSimon Glass free(*str_disk_guid); 5482e192b24SSimon Glass free(parts); 5492e192b24SSimon Glass 5502e192b24SSimon Glass return errno; 5512e192b24SSimon Glass } 5522e192b24SSimon Glass 5534101f687SSimon Glass static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) 5542e192b24SSimon Glass { 5552e192b24SSimon Glass int ret; 5562e192b24SSimon Glass char *str_disk_guid; 5572e192b24SSimon Glass u8 part_count = 0; 5582e192b24SSimon Glass disk_partition_t *partitions = NULL; 5592e192b24SSimon Glass 5602e192b24SSimon Glass /* fill partitions */ 5612e192b24SSimon Glass ret = set_gpt_info(blk_dev_desc, str_part, 5622e192b24SSimon Glass &str_disk_guid, &partitions, &part_count); 5632e192b24SSimon Glass if (ret) { 5642e192b24SSimon Glass if (ret == -1) 5652e192b24SSimon Glass printf("No partition list provided\n"); 5662e192b24SSimon Glass if (ret == -2) 5672e192b24SSimon Glass printf("Missing disk guid\n"); 5682e192b24SSimon Glass if ((ret == -3) || (ret == -4)) 5692e192b24SSimon Glass printf("Partition list incomplete\n"); 5702e192b24SSimon Glass return -1; 5712e192b24SSimon Glass } 5722e192b24SSimon Glass 5732e192b24SSimon Glass /* save partitions layout to disk */ 5742e192b24SSimon Glass ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count); 5752e192b24SSimon Glass free(str_disk_guid); 5762e192b24SSimon Glass free(partitions); 5772e192b24SSimon Glass 5782e192b24SSimon Glass return ret; 5792e192b24SSimon Glass } 5802e192b24SSimon Glass 5814101f687SSimon Glass static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) 5822e192b24SSimon Glass { 5832e192b24SSimon Glass ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, 5842e192b24SSimon Glass blk_dev_desc->blksz); 5852e192b24SSimon Glass disk_partition_t *partitions = NULL; 5862e192b24SSimon Glass gpt_entry *gpt_pte = NULL; 5872e192b24SSimon Glass char *str_disk_guid; 5882e192b24SSimon Glass u8 part_count = 0; 5892e192b24SSimon Glass int ret = 0; 5902e192b24SSimon Glass 5912e192b24SSimon Glass /* fill partitions */ 5922e192b24SSimon Glass ret = set_gpt_info(blk_dev_desc, str_part, 5932e192b24SSimon Glass &str_disk_guid, &partitions, &part_count); 5942e192b24SSimon Glass if (ret) { 5952e192b24SSimon Glass if (ret == -1) { 5962e192b24SSimon Glass printf("No partition list provided - only basic check\n"); 5972e192b24SSimon Glass ret = gpt_verify_headers(blk_dev_desc, gpt_head, 5982e192b24SSimon Glass &gpt_pte); 5992e192b24SSimon Glass goto out; 6002e192b24SSimon Glass } 6012e192b24SSimon Glass if (ret == -2) 6022e192b24SSimon Glass printf("Missing disk guid\n"); 6032e192b24SSimon Glass if ((ret == -3) || (ret == -4)) 6042e192b24SSimon Glass printf("Partition list incomplete\n"); 6052e192b24SSimon Glass return -1; 6062e192b24SSimon Glass } 6072e192b24SSimon Glass 6082e192b24SSimon Glass /* Check partition layout with provided pattern */ 6092e192b24SSimon Glass ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count, 6102e192b24SSimon Glass gpt_head, &gpt_pte); 6112e192b24SSimon Glass free(str_disk_guid); 6122e192b24SSimon Glass free(partitions); 6132e192b24SSimon Glass out: 6142e192b24SSimon Glass free(gpt_pte); 6152e192b24SSimon Glass return ret; 6162e192b24SSimon Glass } 6172e192b24SSimon Glass 61873d6d18bSAlison Chaiken static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) 61973d6d18bSAlison Chaiken { 62073d6d18bSAlison Chaiken int ret; 62173d6d18bSAlison Chaiken char disk_guid[UUID_STR_LEN + 1]; 62273d6d18bSAlison Chaiken 62373d6d18bSAlison Chaiken ret = get_disk_guid(dev_desc, disk_guid); 62473d6d18bSAlison Chaiken if (ret < 0) 62573d6d18bSAlison Chaiken return CMD_RET_FAILURE; 62673d6d18bSAlison Chaiken 62773d6d18bSAlison Chaiken if (namestr) 628382bee57SSimon Glass env_set(namestr, disk_guid); 62973d6d18bSAlison Chaiken else 63073d6d18bSAlison Chaiken printf("%s\n", disk_guid); 63173d6d18bSAlison Chaiken 63273d6d18bSAlison Chaiken return ret; 63373d6d18bSAlison Chaiken } 63473d6d18bSAlison Chaiken 635203f9b48SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME 636*cb40c099SAlison Chaiken /* 637*cb40c099SAlison Chaiken * There are 3 malloc() calls in set_gpt_info() and there is no info about which 638*cb40c099SAlison Chaiken * failed. 639*cb40c099SAlison Chaiken */ 640*cb40c099SAlison Chaiken static void set_gpt_cleanup(char **str_disk_guid, 641*cb40c099SAlison Chaiken disk_partition_t **partitions) 642*cb40c099SAlison Chaiken { 643*cb40c099SAlison Chaiken #ifdef CONFIG_RANDOM_UUID 644*cb40c099SAlison Chaiken if (str_disk_guid) 645*cb40c099SAlison Chaiken free(str_disk_guid); 646*cb40c099SAlison Chaiken #endif 647*cb40c099SAlison Chaiken if (partitions) 648*cb40c099SAlison Chaiken free(partitions); 649*cb40c099SAlison Chaiken } 650*cb40c099SAlison Chaiken 651203f9b48SAlison Chaiken static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, 652203f9b48SAlison Chaiken char *name1, char *name2) 653203f9b48SAlison Chaiken { 654203f9b48SAlison Chaiken struct list_head *pos; 655203f9b48SAlison Chaiken struct disk_part *curr; 656203f9b48SAlison Chaiken disk_partition_t *new_partitions = NULL; 657203f9b48SAlison Chaiken char disk_guid[UUID_STR_LEN + 1]; 658203f9b48SAlison Chaiken char *partitions_list, *str_disk_guid; 659203f9b48SAlison Chaiken u8 part_count = 0; 660203f9b48SAlison Chaiken int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0; 661203f9b48SAlison Chaiken 662203f9b48SAlison Chaiken if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || 663203f9b48SAlison Chaiken (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) 664203f9b48SAlison Chaiken return -EINVAL; 665203f9b48SAlison Chaiken 666203f9b48SAlison Chaiken ret = get_disk_guid(dev_desc, disk_guid); 667203f9b48SAlison Chaiken if (ret < 0) 668203f9b48SAlison Chaiken return ret; 669*cb40c099SAlison Chaiken /* 670*cb40c099SAlison Chaiken * Allocates disk_partitions, requiring matching call to del_gpt_info() 671*cb40c099SAlison Chaiken * if successful. 672*cb40c099SAlison Chaiken */ 673203f9b48SAlison Chaiken numparts = get_gpt_info(dev_desc); 674203f9b48SAlison Chaiken if (numparts <= 0) 675203f9b48SAlison Chaiken return numparts ? numparts : -ENODEV; 676203f9b48SAlison Chaiken 677203f9b48SAlison Chaiken partlistlen = calc_parts_list_len(numparts); 678203f9b48SAlison Chaiken partitions_list = malloc(partlistlen); 679*cb40c099SAlison Chaiken if (!partitions_list) { 680*cb40c099SAlison Chaiken del_gpt_info(); 681203f9b48SAlison Chaiken return -ENOMEM; 682*cb40c099SAlison Chaiken } 683203f9b48SAlison Chaiken memset(partitions_list, '\0', partlistlen); 684203f9b48SAlison Chaiken 685203f9b48SAlison Chaiken ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list); 686*cb40c099SAlison Chaiken if (ret < 0) { 687*cb40c099SAlison Chaiken free(partitions_list); 688203f9b48SAlison Chaiken return ret; 689*cb40c099SAlison Chaiken } 690203f9b48SAlison Chaiken /* 691203f9b48SAlison Chaiken * Uncomment the following line to print a string that 'gpt write' 692203f9b48SAlison Chaiken * or 'gpt verify' will accept as input. 693203f9b48SAlison Chaiken */ 694203f9b48SAlison Chaiken debug("OLD partitions_list is %s with %u chars\n", partitions_list, 695203f9b48SAlison Chaiken (unsigned)strlen(partitions_list)); 696203f9b48SAlison Chaiken 697*cb40c099SAlison Chaiken /* set_gpt_info allocates new_partitions and str_disk_guid */ 698203f9b48SAlison Chaiken ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid, 699203f9b48SAlison Chaiken &new_partitions, &part_count); 700*cb40c099SAlison Chaiken if (ret < 0) { 701*cb40c099SAlison Chaiken del_gpt_info(); 702*cb40c099SAlison Chaiken free(partitions_list); 703*cb40c099SAlison Chaiken if (ret == -ENOMEM) 704*cb40c099SAlison Chaiken set_gpt_cleanup(&str_disk_guid, &new_partitions); 705*cb40c099SAlison Chaiken else 706*cb40c099SAlison Chaiken goto out; 707*cb40c099SAlison Chaiken } 708203f9b48SAlison Chaiken 709203f9b48SAlison Chaiken if (!strcmp(subcomm, "swap")) { 710203f9b48SAlison Chaiken if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) { 711203f9b48SAlison Chaiken printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); 712*cb40c099SAlison Chaiken ret = -EINVAL; 713*cb40c099SAlison Chaiken goto out; 714203f9b48SAlison Chaiken } 715203f9b48SAlison Chaiken list_for_each(pos, &disk_partitions) { 716203f9b48SAlison Chaiken curr = list_entry(pos, struct disk_part, list); 717203f9b48SAlison Chaiken if (!strcmp((char *)curr->gpt_part_info.name, name1)) { 718203f9b48SAlison Chaiken strcpy((char *)curr->gpt_part_info.name, name2); 719203f9b48SAlison Chaiken ctr1++; 720203f9b48SAlison Chaiken } else if (!strcmp((char *)curr->gpt_part_info.name, name2)) { 721203f9b48SAlison Chaiken strcpy((char *)curr->gpt_part_info.name, name1); 722203f9b48SAlison Chaiken ctr2++; 723203f9b48SAlison Chaiken } 724203f9b48SAlison Chaiken } 725203f9b48SAlison Chaiken if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) { 726203f9b48SAlison Chaiken printf("Cannot swap partition names except in pairs.\n"); 727*cb40c099SAlison Chaiken ret = -EINVAL; 728*cb40c099SAlison Chaiken goto out; 729203f9b48SAlison Chaiken } 730203f9b48SAlison Chaiken } else { /* rename */ 731203f9b48SAlison Chaiken if (strlen(name2) > PART_NAME_LEN) { 732203f9b48SAlison Chaiken printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); 733*cb40c099SAlison Chaiken ret = -EINVAL; 734*cb40c099SAlison Chaiken goto out; 735203f9b48SAlison Chaiken } 736203f9b48SAlison Chaiken partnum = (int)simple_strtol(name1, NULL, 10); 737203f9b48SAlison Chaiken if ((partnum < 0) || (partnum > numparts)) { 738203f9b48SAlison Chaiken printf("Illegal partition number %s\n", name1); 739*cb40c099SAlison Chaiken ret = -EINVAL; 740*cb40c099SAlison Chaiken goto out; 741203f9b48SAlison Chaiken } 742203f9b48SAlison Chaiken ret = part_get_info(dev_desc, partnum, new_partitions); 743203f9b48SAlison Chaiken if (ret < 0) 744*cb40c099SAlison Chaiken goto out; 745203f9b48SAlison Chaiken 746203f9b48SAlison Chaiken /* U-Boot partition numbering starts at 1 */ 747203f9b48SAlison Chaiken list_for_each(pos, &disk_partitions) { 748203f9b48SAlison Chaiken curr = list_entry(pos, struct disk_part, list); 749203f9b48SAlison Chaiken if (i == partnum) { 750203f9b48SAlison Chaiken strcpy((char *)curr->gpt_part_info.name, name2); 751203f9b48SAlison Chaiken break; 752203f9b48SAlison Chaiken } 753203f9b48SAlison Chaiken i++; 754203f9b48SAlison Chaiken } 755203f9b48SAlison Chaiken } 756203f9b48SAlison Chaiken 757203f9b48SAlison Chaiken ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list); 758203f9b48SAlison Chaiken if (ret < 0) 759*cb40c099SAlison Chaiken goto out; 760203f9b48SAlison Chaiken debug("NEW partitions_list is %s with %u chars\n", partitions_list, 761203f9b48SAlison Chaiken (unsigned)strlen(partitions_list)); 762203f9b48SAlison Chaiken 763203f9b48SAlison Chaiken ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid, 764203f9b48SAlison Chaiken &new_partitions, &part_count); 765*cb40c099SAlison Chaiken /* 766*cb40c099SAlison Chaiken * Even though valid pointers are here passed into set_gpt_info(), 767*cb40c099SAlison Chaiken * it mallocs again, and there's no way to tell which failed. 768*cb40c099SAlison Chaiken */ 769*cb40c099SAlison Chaiken if (ret < 0) { 770*cb40c099SAlison Chaiken del_gpt_info(); 771*cb40c099SAlison Chaiken free(partitions_list); 772*cb40c099SAlison Chaiken if (ret == -ENOMEM) 773*cb40c099SAlison Chaiken set_gpt_cleanup(&str_disk_guid, &new_partitions); 774*cb40c099SAlison Chaiken else 775*cb40c099SAlison Chaiken goto out; 776*cb40c099SAlison Chaiken } 777203f9b48SAlison Chaiken 778203f9b48SAlison Chaiken debug("Writing new partition table\n"); 779203f9b48SAlison Chaiken ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts); 780203f9b48SAlison Chaiken if (ret < 0) { 781203f9b48SAlison Chaiken printf("Writing new partition table failed\n"); 782*cb40c099SAlison Chaiken goto out; 783203f9b48SAlison Chaiken } 784203f9b48SAlison Chaiken 785203f9b48SAlison Chaiken debug("Reading back new partition table\n"); 786*cb40c099SAlison Chaiken /* 787*cb40c099SAlison Chaiken * Empty the existing disk_partitions list, as otherwise the memory in 788*cb40c099SAlison Chaiken * the original list is unreachable. 789*cb40c099SAlison Chaiken */ 790*cb40c099SAlison Chaiken del_gpt_info(); 791203f9b48SAlison Chaiken numparts = get_gpt_info(dev_desc); 792*cb40c099SAlison Chaiken if (numparts <= 0) { 793*cb40c099SAlison Chaiken ret = numparts ? numparts : -ENODEV; 794*cb40c099SAlison Chaiken goto out; 795*cb40c099SAlison Chaiken } 796203f9b48SAlison Chaiken printf("new partition table with %d partitions is:\n", numparts); 797203f9b48SAlison Chaiken print_gpt_info(); 798203f9b48SAlison Chaiken del_gpt_info(); 799*cb40c099SAlison Chaiken out: 800203f9b48SAlison Chaiken free(new_partitions); 801*cb40c099SAlison Chaiken free(str_disk_guid); 802*cb40c099SAlison Chaiken free(partitions_list); 803203f9b48SAlison Chaiken return ret; 804203f9b48SAlison Chaiken } 805203f9b48SAlison Chaiken #endif 806203f9b48SAlison Chaiken 8072e192b24SSimon Glass /** 8082e192b24SSimon Glass * do_gpt(): Perform GPT operations 8092e192b24SSimon Glass * 8102e192b24SSimon Glass * @param cmdtp - command name 8112e192b24SSimon Glass * @param flag 8122e192b24SSimon Glass * @param argc 8132e192b24SSimon Glass * @param argv 8142e192b24SSimon Glass * 8152e192b24SSimon Glass * @return zero on success; otherwise error 8162e192b24SSimon Glass */ 8172e192b24SSimon Glass static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 8182e192b24SSimon Glass { 8192e192b24SSimon Glass int ret = CMD_RET_SUCCESS; 8202e192b24SSimon Glass int dev = 0; 8212e192b24SSimon Glass char *ep; 8224101f687SSimon Glass struct blk_desc *blk_dev_desc = NULL; 8232e192b24SSimon Glass 824203f9b48SAlison Chaiken #ifndef CONFIG_CMD_GPT_RENAME 8252e192b24SSimon Glass if (argc < 4 || argc > 5) 826203f9b48SAlison Chaiken #else 827203f9b48SAlison Chaiken if (argc < 4 || argc > 6) 828203f9b48SAlison Chaiken #endif 8292e192b24SSimon Glass return CMD_RET_USAGE; 8302e192b24SSimon Glass 8312e192b24SSimon Glass dev = (int)simple_strtoul(argv[3], &ep, 10); 8322e192b24SSimon Glass if (!ep || ep[0] != '\0') { 8332e192b24SSimon Glass printf("'%s' is not a number\n", argv[3]); 8342e192b24SSimon Glass return CMD_RET_USAGE; 8352e192b24SSimon Glass } 836db1d9e78SSimon Glass blk_dev_desc = blk_get_dev(argv[2], dev); 8372e192b24SSimon Glass if (!blk_dev_desc) { 8382e192b24SSimon Glass printf("%s: %s dev %d NOT available\n", 8392e192b24SSimon Glass __func__, argv[2], dev); 8402e192b24SSimon Glass return CMD_RET_FAILURE; 8412e192b24SSimon Glass } 8422e192b24SSimon Glass 8432e192b24SSimon Glass if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { 8442e192b24SSimon Glass printf("Writing GPT: "); 8452e192b24SSimon Glass ret = gpt_default(blk_dev_desc, argv[4]); 8462e192b24SSimon Glass } else if ((strcmp(argv[1], "verify") == 0)) { 8472e192b24SSimon Glass ret = gpt_verify(blk_dev_desc, argv[4]); 8482e192b24SSimon Glass printf("Verify GPT: "); 84973d6d18bSAlison Chaiken } else if (strcmp(argv[1], "guid") == 0) { 85073d6d18bSAlison Chaiken ret = do_disk_guid(blk_dev_desc, argv[4]); 85109a49930SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME 85209a49930SAlison Chaiken } else if (strcmp(argv[1], "read") == 0) { 85309a49930SAlison Chaiken ret = do_get_gpt_info(blk_dev_desc); 854203f9b48SAlison Chaiken } else if ((strcmp(argv[1], "swap") == 0) || 855203f9b48SAlison Chaiken (strcmp(argv[1], "rename") == 0)) { 856203f9b48SAlison Chaiken ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); 85709a49930SAlison Chaiken #endif 8582e192b24SSimon Glass } else { 8592e192b24SSimon Glass return CMD_RET_USAGE; 8602e192b24SSimon Glass } 8612e192b24SSimon Glass 8622e192b24SSimon Glass if (ret) { 8632e192b24SSimon Glass printf("error!\n"); 8642e192b24SSimon Glass return CMD_RET_FAILURE; 8652e192b24SSimon Glass } 8662e192b24SSimon Glass 8672e192b24SSimon Glass printf("success!\n"); 8682e192b24SSimon Glass return CMD_RET_SUCCESS; 8692e192b24SSimon Glass } 8702e192b24SSimon Glass 8712e192b24SSimon Glass U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, 8722e192b24SSimon Glass "GUID Partition Table", 8732e192b24SSimon Glass "<command> <interface> <dev> <partitions_list>\n" 8742e192b24SSimon Glass " - GUID partition table restoration and validity check\n" 8752e192b24SSimon Glass " Restore or verify GPT information on a device connected\n" 8762e192b24SSimon Glass " to interface\n" 8772e192b24SSimon Glass " Example usage:\n" 8782e192b24SSimon Glass " gpt write mmc 0 $partitions\n" 8792e192b24SSimon Glass " gpt verify mmc 0 $partitions\n" 88009a49930SAlison Chaiken " read <interface> <dev>\n" 88109a49930SAlison Chaiken " - read GPT into a data structure for manipulation\n" 88273d6d18bSAlison Chaiken " guid <interface> <dev>\n" 88373d6d18bSAlison Chaiken " - print disk GUID\n" 88473d6d18bSAlison Chaiken " guid <interface> <dev> <varname>\n" 88573d6d18bSAlison Chaiken " - set environment variable to disk GUID\n" 88673d6d18bSAlison Chaiken " Example usage:\n" 88773d6d18bSAlison Chaiken " gpt guid mmc 0\n" 88873d6d18bSAlison Chaiken " gpt guid mmc 0 varname\n" 889203f9b48SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME 890203f9b48SAlison Chaiken "gpt partition renaming commands:\n" 891203f9b48SAlison Chaiken "gpt swap <interface> <dev> <name1> <name2>\n" 892203f9b48SAlison Chaiken " - change all partitions named name1 to name2\n" 893203f9b48SAlison Chaiken " and vice-versa\n" 894203f9b48SAlison Chaiken "gpt rename <interface> <dev> <part> <name>\n" 895203f9b48SAlison Chaiken " - rename the specified partition\n" 896203f9b48SAlison Chaiken " Example usage:\n" 897203f9b48SAlison Chaiken " gpt swap mmc 0 foo bar\n" 898203f9b48SAlison Chaiken " gpt rename mmc 0 3 foo\n" 899203f9b48SAlison Chaiken #endif 9002e192b24SSimon Glass ); 901