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