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 26 static 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 */ 37 static 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 = getenv(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 setenv(s, uuid_str); 64 65 e = getenv(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 */ 96 static 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 */ 133 static 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 159 #ifdef CONFIG_CMD_GPT_RENAME 160 static void del_gpt_info(void) 161 { 162 struct list_head *pos = &disk_partitions; 163 struct disk_part *curr; 164 while (!list_empty(pos)) { 165 curr = list_entry(pos->next, struct disk_part, list); 166 list_del(pos->next); 167 free(curr); 168 } 169 } 170 171 static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum) 172 { 173 struct disk_part *newpart; 174 newpart = malloc(sizeof(*newpart)); 175 if (!newpart) 176 return ERR_PTR(-ENOMEM); 177 memset(newpart, '\0', sizeof(newpart)); 178 179 newpart->gpt_part_info.start = info->start; 180 newpart->gpt_part_info.size = info->size; 181 newpart->gpt_part_info.blksz = info->blksz; 182 strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, 183 PART_NAME_LEN); 184 newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0'; 185 strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, 186 PART_TYPE_LEN); 187 newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; 188 newpart->gpt_part_info.bootable = info->bootable; 189 #ifdef CONFIG_PARTITION_UUIDS 190 strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, 191 UUID_STR_LEN); 192 /* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */ 193 newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0'; 194 #endif 195 newpart->partnum = partnum; 196 197 return newpart; 198 } 199 200 static void prettyprint_part_size(char *sizestr, lbaint_t partsize, 201 lbaint_t blksize) 202 { 203 unsigned long long partbytes, partmegabytes; 204 205 partbytes = partsize * blksize; 206 partmegabytes = lldiv(partbytes, SZ_1M); 207 snprintf(sizestr, 16, "%lluMiB", partmegabytes); 208 } 209 210 static void print_gpt_info(void) 211 { 212 struct list_head *pos; 213 struct disk_part *curr; 214 char partstartstr[16]; 215 char partsizestr[16]; 216 217 list_for_each(pos, &disk_partitions) { 218 curr = list_entry(pos, struct disk_part, list); 219 prettyprint_part_size(partstartstr, curr->gpt_part_info.start, 220 curr->gpt_part_info.blksz); 221 prettyprint_part_size(partsizestr, curr->gpt_part_info.size, 222 curr->gpt_part_info.blksz); 223 224 printf("Partition %d:\n", curr->partnum); 225 printf("Start %s, size %s\n", partstartstr, partsizestr); 226 printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz, 227 curr->gpt_part_info.name); 228 printf("Type %s, bootable %d\n", curr->gpt_part_info.type, 229 curr->gpt_part_info.bootable); 230 #ifdef CONFIG_PARTITION_UUIDS 231 printf("UUID %s\n", curr->gpt_part_info.uuid); 232 #endif 233 printf("\n"); 234 } 235 } 236 237 static int calc_parts_list_len(int numparts) 238 { 239 int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk="); 240 /* for the comma */ 241 partlistlen++; 242 243 /* per-partition additions; numparts starts at 1, so this should be correct */ 244 partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1); 245 /* see part.h for definition of struct disk_partition */ 246 partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); 247 partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); 248 partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); 249 /* for the terminating null */ 250 partlistlen++; 251 debug("Length of partitions_list is %d for %d partitions\n", partlistlen, 252 numparts); 253 return partlistlen; 254 } 255 256 /* 257 * create the string that upstream 'gpt write' command will accept as an 258 * argument 259 * 260 * From doc/README.gpt, Format of partitions layout: 261 * "uuid_disk=...;name=u-boot,size=60MiB,uuid=...; 262 * name=kernel,size=60MiB,uuid=...;" 263 * The fields 'name' and 'size' are mandatory for every partition. 264 * The field 'start' is optional. The fields 'uuid' and 'uuid_disk' 265 * are optional if CONFIG_RANDOM_UUID is enabled. 266 */ 267 static int create_gpt_partitions_list(int numparts, const char *guid, 268 char *partitions_list) 269 { 270 struct list_head *pos; 271 struct disk_part *curr; 272 char partstr[PART_NAME_LEN + 1]; 273 274 if (!partitions_list) 275 return -EINVAL; 276 277 strcpy(partitions_list, "uuid_disk="); 278 strncat(partitions_list, guid, UUID_STR_LEN + 1); 279 strcat(partitions_list, ";"); 280 281 list_for_each(pos, &disk_partitions) { 282 curr = list_entry(pos, struct disk_part, list); 283 strcat(partitions_list, "name="); 284 strncat(partitions_list, (const char *)curr->gpt_part_info.name, 285 PART_NAME_LEN + 1); 286 strcat(partitions_list, ",start="); 287 prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start, 288 (unsigned long) curr->gpt_part_info.blksz); 289 /* one extra byte for NULL */ 290 strncat(partitions_list, partstr, PART_NAME_LEN + 1); 291 strcat(partitions_list, ",size="); 292 prettyprint_part_size(partstr, curr->gpt_part_info.size, 293 curr->gpt_part_info.blksz); 294 strncat(partitions_list, partstr, PART_NAME_LEN + 1); 295 296 strcat(partitions_list, ",uuid="); 297 strncat(partitions_list, curr->gpt_part_info.uuid, 298 UUID_STR_LEN + 1); 299 strcat(partitions_list, ";"); 300 } 301 return 0; 302 } 303 304 /* 305 * read partition info into disk_partitions list where 306 * it can be printed or modified 307 */ 308 static int get_gpt_info(struct blk_desc *dev_desc) 309 { 310 /* start partition numbering at 1, as U-Boot does */ 311 int valid_parts = 0, p, ret; 312 disk_partition_t info; 313 struct disk_part *new_disk_part; 314 315 /* 316 * Always re-read partition info from device, in case 317 * it has changed 318 */ 319 INIT_LIST_HEAD(&disk_partitions); 320 321 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 322 ret = part_get_info(dev_desc, p, &info); 323 if (ret) 324 continue; 325 326 /* Add 1 here because counter is zero-based but p1 is 327 the first partition */ 328 new_disk_part = allocate_disk_part(&info, valid_parts+1); 329 if (IS_ERR(new_disk_part)) 330 goto out; 331 332 list_add_tail(&new_disk_part->list, &disk_partitions); 333 valid_parts++; 334 } 335 if (valid_parts == 0) { 336 printf("** No valid partitions found **\n"); 337 goto out; 338 } 339 return valid_parts; 340 out: 341 if (valid_parts >= 1) 342 del_gpt_info(); 343 return -ENODEV; 344 } 345 346 /* a wrapper to test get_gpt_info */ 347 static int do_get_gpt_info(struct blk_desc *dev_desc) 348 { 349 int ret; 350 351 ret = get_gpt_info(dev_desc); 352 if (ret > 0) { 353 print_gpt_info(); 354 del_gpt_info(); 355 return 0; 356 } 357 return ret; 358 } 359 #endif 360 361 /** 362 * set_gpt_info(): Fill partition information from string 363 * function allocates memory, remember to free! 364 * 365 * @param dev_desc - pointer block device descriptor 366 * @param str_part - pointer to string with partition information 367 * @param str_disk_guid - pointer to pointer to allocated string with disk guid 368 * @param partitions - pointer to pointer to allocated partitions array 369 * @param parts_count - number of partitions 370 * 371 * @return - zero on success, otherwise error 372 * 373 */ 374 static int set_gpt_info(struct blk_desc *dev_desc, 375 const char *str_part, 376 char **str_disk_guid, 377 disk_partition_t **partitions, 378 u8 *parts_count) 379 { 380 char *tok, *str, *s; 381 int i; 382 char *val, *p; 383 int p_count; 384 disk_partition_t *parts; 385 int errno = 0; 386 uint64_t size_ll, start_ll; 387 lbaint_t offset = 0; 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 gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD); 406 #else 407 free(str); 408 return -2; 409 #endif 410 } else { 411 val = strsep(&val, ";"); 412 if (extract_env(val, &p)) 413 p = val; 414 *str_disk_guid = strdup(p); 415 free(val); 416 /* Move s to first partition */ 417 strsep(&s, ";"); 418 } 419 if (strlen(s) == 0) 420 return -3; 421 422 i = strlen(s) - 1; 423 if (s[i] == ';') 424 s[i] = '\0'; 425 426 /* calculate expected number of partitions */ 427 p_count = 1; 428 p = s; 429 while (*p) { 430 if (*p++ == ';') 431 p_count++; 432 } 433 434 /* allocate memory for partitions */ 435 parts = calloc(sizeof(disk_partition_t), p_count); 436 437 /* retrieve partitions data from string */ 438 for (i = 0; i < p_count; i++) { 439 tok = strsep(&s, ";"); 440 441 if (tok == NULL) 442 break; 443 444 /* uuid */ 445 val = extract_val(tok, "uuid"); 446 if (!val) { 447 /* 'uuid' is optional if random uuid's are enabled */ 448 #ifdef CONFIG_RANDOM_UUID 449 gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD); 450 #else 451 errno = -4; 452 goto err; 453 #endif 454 } else { 455 if (extract_env(val, &p)) 456 p = val; 457 if (strlen(p) >= sizeof(parts[i].uuid)) { 458 printf("Wrong uuid format for partition %d\n", i); 459 errno = -4; 460 goto err; 461 } 462 strcpy((char *)parts[i].uuid, p); 463 free(val); 464 } 465 #ifdef CONFIG_PARTITION_TYPE_GUID 466 /* guid */ 467 val = extract_val(tok, "type"); 468 if (val) { 469 /* 'type' is optional */ 470 if (extract_env(val, &p)) 471 p = val; 472 if (strlen(p) >= sizeof(parts[i].type_guid)) { 473 printf("Wrong type guid format for partition %d\n", 474 i); 475 errno = -4; 476 goto err; 477 } 478 strcpy((char *)parts[i].type_guid, p); 479 free(val); 480 } 481 #endif 482 /* name */ 483 val = extract_val(tok, "name"); 484 if (!val) { /* name is mandatory */ 485 errno = -4; 486 goto err; 487 } 488 if (extract_env(val, &p)) 489 p = val; 490 if (strlen(p) >= sizeof(parts[i].name)) { 491 errno = -4; 492 goto err; 493 } 494 strcpy((char *)parts[i].name, p); 495 free(val); 496 497 /* size */ 498 val = extract_val(tok, "size"); 499 if (!val) { /* 'size' is mandatory */ 500 errno = -4; 501 goto err; 502 } 503 if (extract_env(val, &p)) 504 p = val; 505 if ((strcmp(p, "-") == 0)) { 506 /* Let part efi module to auto extend the size */ 507 parts[i].size = 0; 508 } else { 509 size_ll = ustrtoull(p, &p, 0); 510 parts[i].size = lldiv(size_ll, dev_desc->blksz); 511 } 512 513 free(val); 514 515 /* start address */ 516 val = extract_val(tok, "start"); 517 if (val) { /* start address is optional */ 518 if (extract_env(val, &p)) 519 p = val; 520 start_ll = ustrtoull(p, &p, 0); 521 parts[i].start = lldiv(start_ll, dev_desc->blksz); 522 free(val); 523 } 524 525 offset += parts[i].size + parts[i].start; 526 527 /* bootable */ 528 if (found_key(tok, "bootable")) 529 parts[i].bootable = 1; 530 } 531 532 *parts_count = p_count; 533 *partitions = parts; 534 free(str); 535 536 return 0; 537 err: 538 free(str); 539 free(*str_disk_guid); 540 free(parts); 541 542 return errno; 543 } 544 545 static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) 546 { 547 int ret; 548 char *str_disk_guid; 549 u8 part_count = 0; 550 disk_partition_t *partitions = NULL; 551 552 /* fill partitions */ 553 ret = set_gpt_info(blk_dev_desc, str_part, 554 &str_disk_guid, &partitions, &part_count); 555 if (ret) { 556 if (ret == -1) 557 printf("No partition list provided\n"); 558 if (ret == -2) 559 printf("Missing disk guid\n"); 560 if ((ret == -3) || (ret == -4)) 561 printf("Partition list incomplete\n"); 562 return -1; 563 } 564 565 /* save partitions layout to disk */ 566 ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count); 567 free(str_disk_guid); 568 free(partitions); 569 570 return ret; 571 } 572 573 static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) 574 { 575 ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, 576 blk_dev_desc->blksz); 577 disk_partition_t *partitions = NULL; 578 gpt_entry *gpt_pte = NULL; 579 char *str_disk_guid; 580 u8 part_count = 0; 581 int ret = 0; 582 583 /* fill partitions */ 584 ret = set_gpt_info(blk_dev_desc, str_part, 585 &str_disk_guid, &partitions, &part_count); 586 if (ret) { 587 if (ret == -1) { 588 printf("No partition list provided - only basic check\n"); 589 ret = gpt_verify_headers(blk_dev_desc, gpt_head, 590 &gpt_pte); 591 goto out; 592 } 593 if (ret == -2) 594 printf("Missing disk guid\n"); 595 if ((ret == -3) || (ret == -4)) 596 printf("Partition list incomplete\n"); 597 return -1; 598 } 599 600 /* Check partition layout with provided pattern */ 601 ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count, 602 gpt_head, &gpt_pte); 603 free(str_disk_guid); 604 free(partitions); 605 out: 606 free(gpt_pte); 607 return ret; 608 } 609 610 static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) 611 { 612 int ret; 613 char disk_guid[UUID_STR_LEN + 1]; 614 615 ret = get_disk_guid(dev_desc, disk_guid); 616 if (ret < 0) 617 return CMD_RET_FAILURE; 618 619 if (namestr) 620 setenv(namestr, disk_guid); 621 else 622 printf("%s\n", disk_guid); 623 624 return ret; 625 } 626 627 #ifdef CONFIG_CMD_GPT_RENAME 628 static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, 629 char *name1, char *name2) 630 { 631 struct list_head *pos; 632 struct disk_part *curr; 633 disk_partition_t *new_partitions = NULL; 634 char disk_guid[UUID_STR_LEN + 1]; 635 char *partitions_list, *str_disk_guid; 636 u8 part_count = 0; 637 int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0; 638 639 if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || 640 (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) 641 return -EINVAL; 642 643 ret = get_disk_guid(dev_desc, disk_guid); 644 if (ret < 0) 645 return ret; 646 numparts = get_gpt_info(dev_desc); 647 if (numparts <= 0) 648 return numparts ? numparts : -ENODEV; 649 650 partlistlen = calc_parts_list_len(numparts); 651 partitions_list = malloc(partlistlen); 652 if (partitions_list == NULL) 653 return -ENOMEM; 654 memset(partitions_list, '\0', partlistlen); 655 656 ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list); 657 if (ret < 0) 658 return ret; 659 /* 660 * Uncomment the following line to print a string that 'gpt write' 661 * or 'gpt verify' will accept as input. 662 */ 663 debug("OLD partitions_list is %s with %u chars\n", partitions_list, 664 (unsigned)strlen(partitions_list)); 665 666 ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid, 667 &new_partitions, &part_count); 668 if (ret < 0) 669 return ret; 670 671 if (!strcmp(subcomm, "swap")) { 672 if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) { 673 printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); 674 return -EINVAL; 675 } 676 list_for_each(pos, &disk_partitions) { 677 curr = list_entry(pos, struct disk_part, list); 678 if (!strcmp((char *)curr->gpt_part_info.name, name1)) { 679 strcpy((char *)curr->gpt_part_info.name, name2); 680 ctr1++; 681 } else if (!strcmp((char *)curr->gpt_part_info.name, name2)) { 682 strcpy((char *)curr->gpt_part_info.name, name1); 683 ctr2++; 684 } 685 } 686 if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) { 687 printf("Cannot swap partition names except in pairs.\n"); 688 return -EINVAL; 689 } 690 } else { /* rename */ 691 if (strlen(name2) > PART_NAME_LEN) { 692 printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); 693 return -EINVAL; 694 } 695 partnum = (int)simple_strtol(name1, NULL, 10); 696 if ((partnum < 0) || (partnum > numparts)) { 697 printf("Illegal partition number %s\n", name1); 698 return -EINVAL; 699 } 700 ret = part_get_info(dev_desc, partnum, new_partitions); 701 if (ret < 0) 702 return ret; 703 704 /* U-Boot partition numbering starts at 1 */ 705 list_for_each(pos, &disk_partitions) { 706 curr = list_entry(pos, struct disk_part, list); 707 if (i == partnum) { 708 strcpy((char *)curr->gpt_part_info.name, name2); 709 break; 710 } 711 i++; 712 } 713 } 714 715 ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list); 716 if (ret < 0) 717 return ret; 718 debug("NEW partitions_list is %s with %u chars\n", partitions_list, 719 (unsigned)strlen(partitions_list)); 720 721 ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid, 722 &new_partitions, &part_count); 723 if (ret < 0) 724 return ret; 725 726 debug("Writing new partition table\n"); 727 ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts); 728 if (ret < 0) { 729 printf("Writing new partition table failed\n"); 730 return ret; 731 } 732 733 debug("Reading back new partition table\n"); 734 numparts = get_gpt_info(dev_desc); 735 if (numparts <= 0) 736 return numparts ? numparts : -ENODEV; 737 printf("new partition table with %d partitions is:\n", numparts); 738 print_gpt_info(); 739 740 del_gpt_info(); 741 free(partitions_list); 742 free(str_disk_guid); 743 free(new_partitions); 744 return ret; 745 } 746 #endif 747 748 /** 749 * do_gpt(): Perform GPT operations 750 * 751 * @param cmdtp - command name 752 * @param flag 753 * @param argc 754 * @param argv 755 * 756 * @return zero on success; otherwise error 757 */ 758 static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 759 { 760 int ret = CMD_RET_SUCCESS; 761 int dev = 0; 762 char *ep; 763 struct blk_desc *blk_dev_desc = NULL; 764 765 #ifndef CONFIG_CMD_GPT_RENAME 766 if (argc < 4 || argc > 5) 767 #else 768 if (argc < 4 || argc > 6) 769 #endif 770 return CMD_RET_USAGE; 771 772 dev = (int)simple_strtoul(argv[3], &ep, 10); 773 if (!ep || ep[0] != '\0') { 774 printf("'%s' is not a number\n", argv[3]); 775 return CMD_RET_USAGE; 776 } 777 blk_dev_desc = blk_get_dev(argv[2], dev); 778 if (!blk_dev_desc) { 779 printf("%s: %s dev %d NOT available\n", 780 __func__, argv[2], dev); 781 return CMD_RET_FAILURE; 782 } 783 784 if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { 785 printf("Writing GPT: "); 786 ret = gpt_default(blk_dev_desc, argv[4]); 787 } else if ((strcmp(argv[1], "verify") == 0)) { 788 ret = gpt_verify(blk_dev_desc, argv[4]); 789 printf("Verify GPT: "); 790 } else if (strcmp(argv[1], "guid") == 0) { 791 ret = do_disk_guid(blk_dev_desc, argv[4]); 792 #ifdef CONFIG_CMD_GPT_RENAME 793 } else if (strcmp(argv[1], "read") == 0) { 794 ret = do_get_gpt_info(blk_dev_desc); 795 } else if ((strcmp(argv[1], "swap") == 0) || 796 (strcmp(argv[1], "rename") == 0)) { 797 ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); 798 #endif 799 } else { 800 return CMD_RET_USAGE; 801 } 802 803 if (ret) { 804 printf("error!\n"); 805 return CMD_RET_FAILURE; 806 } 807 808 printf("success!\n"); 809 return CMD_RET_SUCCESS; 810 } 811 812 U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, 813 "GUID Partition Table", 814 "<command> <interface> <dev> <partitions_list>\n" 815 " - GUID partition table restoration and validity check\n" 816 " Restore or verify GPT information on a device connected\n" 817 " to interface\n" 818 " Example usage:\n" 819 " gpt write mmc 0 $partitions\n" 820 " gpt verify mmc 0 $partitions\n" 821 " read <interface> <dev>\n" 822 " - read GPT into a data structure for manipulation\n" 823 " guid <interface> <dev>\n" 824 " - print disk GUID\n" 825 " guid <interface> <dev> <varname>\n" 826 " - set environment variable to disk GUID\n" 827 " Example usage:\n" 828 " gpt guid mmc 0\n" 829 " gpt guid mmc 0 varname\n" 830 #ifdef CONFIG_CMD_GPT_RENAME 831 "gpt partition renaming commands:\n" 832 "gpt swap <interface> <dev> <name1> <name2>\n" 833 " - change all partitions named name1 to name2\n" 834 " and vice-versa\n" 835 "gpt rename <interface> <dev> <part> <name>\n" 836 " - rename the specified partition\n" 837 " Example usage:\n" 838 " gpt swap mmc 0 foo bar\n" 839 " gpt rename mmc 0 3 foo\n" 840 #endif 841 ); 842