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