Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
8b096237 PW |
2 | /* |
3 | * cmd_gpt.c -- GPT (GUID Partition Table) handling command | |
4 | * | |
bbb9ffac LM |
5 | * Copyright (C) 2015 |
6 | * Lukasz Majewski <l.majewski@majess.pl> | |
7 | * | |
8b096237 PW |
8 | * Copyright (C) 2012 Samsung Electronics |
9 | * author: Lukasz Majewski <l.majewski@samsung.com> | |
10 | * author: Piotr Wilczek <p.wilczek@samsung.com> | |
8b096237 PW |
11 | */ |
12 | ||
13 | #include <common.h> | |
e6f6f9e6 | 14 | #include <blk.h> |
9fb625ce | 15 | #include <env.h> |
f7ae49fc | 16 | #include <log.h> |
8b096237 PW |
17 | #include <malloc.h> |
18 | #include <command.h> | |
e6f6f9e6 | 19 | #include <part.h> |
8b096237 | 20 | #include <part_efi.h> |
12fc1f3b | 21 | #include <part.h> |
8b096237 | 22 | #include <exports.h> |
ba06b3c5 | 23 | #include <uuid.h> |
8b096237 | 24 | #include <linux/ctype.h> |
3e34cf7b | 25 | #include <div64.h> |
bbb9ffac | 26 | #include <memalign.h> |
09a49930 | 27 | #include <linux/compat.h> |
61b29b82 | 28 | #include <linux/err.h> |
203f9b48 AC |
29 | #include <linux/sizes.h> |
30 | #include <stdlib.h> | |
09a49930 AC |
31 | |
32 | static LIST_HEAD(disk_partitions); | |
8b096237 | 33 | |
8b096237 PW |
34 | /** |
35 | * extract_env(): Expand env name from string format '&{env_name}' | |
36 | * and return pointer to the env (if the env is set) | |
37 | * | |
38 | * @param str - pointer to string | |
39 | * @param env - pointer to pointer to extracted env | |
40 | * | |
185f812c | 41 | * Return: - zero on successful expand and env is set |
8b096237 | 42 | */ |
39206382 | 43 | static int extract_env(const char *str, char **env) |
8b096237 | 44 | { |
39206382 | 45 | int ret = -1; |
8b096237 | 46 | char *e, *s; |
39206382 PM |
47 | #ifdef CONFIG_RANDOM_UUID |
48 | char uuid_str[UUID_STR_LEN + 1]; | |
49 | #endif | |
8b096237 PW |
50 | |
51 | if (!str || strlen(str) < 4) | |
52 | return -1; | |
53 | ||
39206382 PM |
54 | if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}'))) |
55 | return -1; | |
56 | ||
57 | s = strdup(str); | |
58 | if (s == NULL) | |
59 | return -1; | |
60 | ||
61 | memset(s + strlen(s) - 1, '\0', 1); | |
62 | memmove(s, s + 2, strlen(s) - 1); | |
63 | ||
00caae6d | 64 | e = env_get(s); |
39206382 PM |
65 | if (e == NULL) { |
66 | #ifdef CONFIG_RANDOM_UUID | |
67 | debug("%s unset. ", str); | |
9da52f8f | 68 | gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID); |
382bee57 | 69 | env_set(s, uuid_str); |
39206382 | 70 | |
00caae6d | 71 | e = env_get(s); |
39206382 PM |
72 | if (e) { |
73 | debug("Set to random.\n"); | |
74 | ret = 0; | |
75 | } else { | |
76 | debug("Can't get random UUID.\n"); | |
8b096237 | 77 | } |
39206382 PM |
78 | #else |
79 | debug("%s unset.\n", str); | |
80 | #endif | |
81 | } else { | |
82 | debug("%s get from environment.\n", str); | |
83 | ret = 0; | |
8b096237 PW |
84 | } |
85 | ||
39206382 PM |
86 | *env = e; |
87 | free(s); | |
88 | ||
89 | return ret; | |
8b096237 PW |
90 | } |
91 | ||
92 | /** | |
93 | * extract_val(): Extract value from a key=value pair list (comma separated). | |
94 | * Only value for the given key is returend. | |
95 | * Function allocates memory for the value, remember to free! | |
96 | * | |
97 | * @param str - pointer to string with key=values pairs | |
98 | * @param key - pointer to the key to search for | |
99 | * | |
185f812c | 100 | * Return: - pointer to allocated string with the value |
8b096237 PW |
101 | */ |
102 | static char *extract_val(const char *str, const char *key) | |
103 | { | |
104 | char *v, *k; | |
105 | char *s, *strcopy; | |
106 | char *new = NULL; | |
107 | ||
108 | strcopy = strdup(str); | |
109 | if (strcopy == NULL) | |
110 | return NULL; | |
111 | ||
112 | s = strcopy; | |
113 | while (s) { | |
114 | v = strsep(&s, ","); | |
115 | if (!v) | |
116 | break; | |
117 | k = strsep(&v, "="); | |
118 | if (!k) | |
119 | break; | |
120 | if (strcmp(k, key) == 0) { | |
121 | new = strdup(v); | |
122 | break; | |
123 | } | |
124 | } | |
125 | ||
126 | free(strcopy); | |
127 | ||
128 | return new; | |
129 | } | |
130 | ||
cfdaf4ca PD |
131 | /** |
132 | * found_key(): Found key without value in parameter list (comma separated). | |
133 | * | |
134 | * @param str - pointer to string with key | |
135 | * @param key - pointer to the key to search for | |
136 | * | |
185f812c | 137 | * Return: - true on found key |
cfdaf4ca PD |
138 | */ |
139 | static bool found_key(const char *str, const char *key) | |
140 | { | |
141 | char *k; | |
142 | char *s, *strcopy; | |
143 | bool result = false; | |
144 | ||
145 | strcopy = strdup(str); | |
146 | if (!strcopy) | |
147 | return NULL; | |
148 | ||
149 | s = strcopy; | |
150 | while (s) { | |
151 | k = strsep(&s, ","); | |
152 | if (!k) | |
153 | break; | |
154 | if (strcmp(k, key) == 0) { | |
155 | result = true; | |
156 | break; | |
157 | } | |
158 | } | |
159 | ||
160 | free(strcopy); | |
161 | ||
162 | return result; | |
163 | } | |
164 | ||
2fcaa413 AC |
165 | static int calc_parts_list_len(int numparts) |
166 | { | |
167 | int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk="); | |
168 | /* for the comma */ | |
169 | partlistlen++; | |
170 | ||
171 | /* per-partition additions; numparts starts at 1, so this should be correct */ | |
172 | partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1); | |
173 | /* see part.h for definition of struct disk_partition */ | |
174 | partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); | |
175 | partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); | |
368beaf7 JW |
176 | #ifdef CONFIG_PARTITION_TYPE_GUID |
177 | partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); | |
178 | #endif | |
648140f7 | 179 | partlistlen += numparts * strlen("bootable,"); |
2fcaa413 AC |
180 | partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); |
181 | /* for the terminating null */ | |
182 | partlistlen++; | |
183 | debug("Length of partitions_list is %d for %d partitions\n", partlistlen, | |
184 | numparts); | |
185 | return partlistlen; | |
186 | } | |
187 | ||
09a49930 AC |
188 | #ifdef CONFIG_CMD_GPT_RENAME |
189 | static void del_gpt_info(void) | |
190 | { | |
191 | struct list_head *pos = &disk_partitions; | |
192 | struct disk_part *curr; | |
193 | while (!list_empty(pos)) { | |
194 | curr = list_entry(pos->next, struct disk_part, list); | |
195 | list_del(pos->next); | |
196 | free(curr); | |
197 | } | |
198 | } | |
199 | ||
0528979f SG |
200 | static struct disk_part *allocate_disk_part(struct disk_partition *info, |
201 | int partnum) | |
09a49930 AC |
202 | { |
203 | struct disk_part *newpart; | |
f66bc0e0 | 204 | newpart = calloc(1, sizeof(struct disk_part)); |
09a49930 AC |
205 | if (!newpart) |
206 | return ERR_PTR(-ENOMEM); | |
09a49930 AC |
207 | |
208 | newpart->gpt_part_info.start = info->start; | |
209 | newpart->gpt_part_info.size = info->size; | |
210 | newpart->gpt_part_info.blksz = info->blksz; | |
211 | strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, | |
212 | PART_NAME_LEN); | |
213 | newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0'; | |
214 | strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, | |
215 | PART_TYPE_LEN); | |
216 | newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; | |
217 | newpart->gpt_part_info.bootable = info->bootable; | |
368beaf7 JW |
218 | #ifdef CONFIG_PARTITION_TYPE_GUID |
219 | strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid, | |
220 | UUID_STR_LEN); | |
221 | newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0'; | |
222 | #endif | |
c5f1d005 SG |
223 | if (IS_ENABLED(CONFIG_PARTITION_UUIDS)) { |
224 | strlcpy(newpart->gpt_part_info.uuid, disk_partition_uuid(info), | |
225 | UUID_STR_LEN + 1); | |
226 | } | |
09a49930 AC |
227 | newpart->partnum = partnum; |
228 | ||
229 | return newpart; | |
230 | } | |
231 | ||
203f9b48 AC |
232 | static void prettyprint_part_size(char *sizestr, lbaint_t partsize, |
233 | lbaint_t blksize) | |
234 | { | |
235 | unsigned long long partbytes, partmegabytes; | |
236 | ||
237 | partbytes = partsize * blksize; | |
238 | partmegabytes = lldiv(partbytes, SZ_1M); | |
239 | snprintf(sizestr, 16, "%lluMiB", partmegabytes); | |
240 | } | |
241 | ||
09a49930 AC |
242 | static void print_gpt_info(void) |
243 | { | |
244 | struct list_head *pos; | |
245 | struct disk_part *curr; | |
203f9b48 AC |
246 | char partstartstr[16]; |
247 | char partsizestr[16]; | |
09a49930 AC |
248 | |
249 | list_for_each(pos, &disk_partitions) { | |
250 | curr = list_entry(pos, struct disk_part, list); | |
203f9b48 AC |
251 | prettyprint_part_size(partstartstr, curr->gpt_part_info.start, |
252 | curr->gpt_part_info.blksz); | |
253 | prettyprint_part_size(partsizestr, curr->gpt_part_info.size, | |
254 | curr->gpt_part_info.blksz); | |
255 | ||
09a49930 | 256 | printf("Partition %d:\n", curr->partnum); |
203f9b48 | 257 | printf("Start %s, size %s\n", partstartstr, partsizestr); |
09a49930 AC |
258 | printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz, |
259 | curr->gpt_part_info.name); | |
260 | printf("Type %s, bootable %d\n", curr->gpt_part_info.type, | |
25801acc | 261 | curr->gpt_part_info.bootable & PART_BOOTABLE); |
368beaf7 JW |
262 | #ifdef CONFIG_PARTITION_TYPE_GUID |
263 | printf("Type GUID %s\n", curr->gpt_part_info.type_guid); | |
264 | #endif | |
09a49930 AC |
265 | #ifdef CONFIG_PARTITION_UUIDS |
266 | printf("UUID %s\n", curr->gpt_part_info.uuid); | |
267 | #endif | |
268 | printf("\n"); | |
269 | } | |
270 | } | |
271 | ||
203f9b48 AC |
272 | /* |
273 | * create the string that upstream 'gpt write' command will accept as an | |
274 | * argument | |
275 | * | |
276 | * From doc/README.gpt, Format of partitions layout: | |
277 | * "uuid_disk=...;name=u-boot,size=60MiB,uuid=...; | |
278 | * name=kernel,size=60MiB,uuid=...;" | |
279 | * The fields 'name' and 'size' are mandatory for every partition. | |
280 | * The field 'start' is optional. The fields 'uuid' and 'uuid_disk' | |
281 | * are optional if CONFIG_RANDOM_UUID is enabled. | |
282 | */ | |
283 | static int create_gpt_partitions_list(int numparts, const char *guid, | |
284 | char *partitions_list) | |
285 | { | |
286 | struct list_head *pos; | |
287 | struct disk_part *curr; | |
288 | char partstr[PART_NAME_LEN + 1]; | |
289 | ||
290 | if (!partitions_list) | |
291 | return -EINVAL; | |
292 | ||
293 | strcpy(partitions_list, "uuid_disk="); | |
294 | strncat(partitions_list, guid, UUID_STR_LEN + 1); | |
295 | strcat(partitions_list, ";"); | |
296 | ||
297 | list_for_each(pos, &disk_partitions) { | |
298 | curr = list_entry(pos, struct disk_part, list); | |
299 | strcat(partitions_list, "name="); | |
300 | strncat(partitions_list, (const char *)curr->gpt_part_info.name, | |
301 | PART_NAME_LEN + 1); | |
3a2605fa PD |
302 | sprintf(partstr, ",start=0x%llx", |
303 | (unsigned long long)curr->gpt_part_info.start * | |
304 | curr->gpt_part_info.blksz); | |
203f9b48 AC |
305 | /* one extra byte for NULL */ |
306 | strncat(partitions_list, partstr, PART_NAME_LEN + 1); | |
3a2605fa PD |
307 | sprintf(partstr, ",size=0x%llx", |
308 | (unsigned long long)curr->gpt_part_info.size * | |
309 | curr->gpt_part_info.blksz); | |
203f9b48 AC |
310 | strncat(partitions_list, partstr, PART_NAME_LEN + 1); |
311 | ||
368beaf7 JW |
312 | #ifdef CONFIG_PARTITION_TYPE_GUID |
313 | strcat(partitions_list, ",type="); | |
314 | strncat(partitions_list, curr->gpt_part_info.type_guid, | |
315 | UUID_STR_LEN + 1); | |
316 | #endif | |
203f9b48 AC |
317 | strcat(partitions_list, ",uuid="); |
318 | strncat(partitions_list, curr->gpt_part_info.uuid, | |
319 | UUID_STR_LEN + 1); | |
648140f7 JW |
320 | if (curr->gpt_part_info.bootable & PART_BOOTABLE) |
321 | strcat(partitions_list, ",bootable"); | |
203f9b48 AC |
322 | strcat(partitions_list, ";"); |
323 | } | |
324 | return 0; | |
325 | } | |
326 | ||
09a49930 AC |
327 | /* |
328 | * read partition info into disk_partitions list where | |
329 | * it can be printed or modified | |
330 | */ | |
331 | static int get_gpt_info(struct blk_desc *dev_desc) | |
332 | { | |
333 | /* start partition numbering at 1, as U-Boot does */ | |
334 | int valid_parts = 0, p, ret; | |
0528979f | 335 | struct disk_partition info; |
09a49930 AC |
336 | struct disk_part *new_disk_part; |
337 | ||
203f9b48 AC |
338 | /* |
339 | * Always re-read partition info from device, in case | |
340 | * it has changed | |
341 | */ | |
342 | INIT_LIST_HEAD(&disk_partitions); | |
09a49930 AC |
343 | |
344 | for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { | |
345 | ret = part_get_info(dev_desc, p, &info); | |
346 | if (ret) | |
347 | continue; | |
348 | ||
349 | /* Add 1 here because counter is zero-based but p1 is | |
350 | the first partition */ | |
351 | new_disk_part = allocate_disk_part(&info, valid_parts+1); | |
352 | if (IS_ERR(new_disk_part)) | |
353 | goto out; | |
354 | ||
355 | list_add_tail(&new_disk_part->list, &disk_partitions); | |
356 | valid_parts++; | |
357 | } | |
358 | if (valid_parts == 0) { | |
359 | printf("** No valid partitions found **\n"); | |
360 | goto out; | |
361 | } | |
362 | return valid_parts; | |
363 | out: | |
364 | if (valid_parts >= 1) | |
365 | del_gpt_info(); | |
366 | return -ENODEV; | |
367 | } | |
368 | ||
369 | /* a wrapper to test get_gpt_info */ | |
653cd92d | 370 | static int do_get_gpt_info(struct blk_desc *dev_desc, char * const namestr) |
09a49930 | 371 | { |
653cd92d FA |
372 | int numparts; |
373 | ||
374 | numparts = get_gpt_info(dev_desc); | |
375 | ||
376 | if (numparts > 0) { | |
377 | if (namestr) { | |
378 | char disk_guid[UUID_STR_LEN + 1]; | |
379 | char *partitions_list; | |
380 | int partlistlen; | |
381 | int ret = -1; | |
382 | ||
383 | ret = get_disk_guid(dev_desc, disk_guid); | |
384 | if (ret < 0) | |
385 | return ret; | |
386 | ||
387 | partlistlen = calc_parts_list_len(numparts); | |
388 | partitions_list = malloc(partlistlen); | |
389 | if (!partitions_list) { | |
390 | del_gpt_info(); | |
391 | return -ENOMEM; | |
392 | } | |
393 | memset(partitions_list, '\0', partlistlen); | |
394 | ||
395 | ret = create_gpt_partitions_list(numparts, disk_guid, | |
396 | partitions_list); | |
397 | if (ret < 0) | |
398 | printf("Error: Could not create partition list string!\n"); | |
399 | else | |
400 | env_set(namestr, partitions_list); | |
09a49930 | 401 | |
653cd92d FA |
402 | free(partitions_list); |
403 | } else { | |
404 | print_gpt_info(); | |
405 | } | |
09a49930 AC |
406 | del_gpt_info(); |
407 | return 0; | |
408 | } | |
653cd92d | 409 | return numparts; |
09a49930 AC |
410 | } |
411 | #endif | |
412 | ||
8b096237 PW |
413 | /** |
414 | * set_gpt_info(): Fill partition information from string | |
415 | * function allocates memory, remember to free! | |
416 | * | |
417 | * @param dev_desc - pointer block device descriptor | |
418 | * @param str_part - pointer to string with partition information | |
419 | * @param str_disk_guid - pointer to pointer to allocated string with disk guid | |
420 | * @param partitions - pointer to pointer to allocated partitions array | |
421 | * @param parts_count - number of partitions | |
422 | * | |
185f812c | 423 | * Return: - zero on success, otherwise error |
8b096237 PW |
424 | * |
425 | */ | |
4101f687 | 426 | static int set_gpt_info(struct blk_desc *dev_desc, |
8b096237 PW |
427 | const char *str_part, |
428 | char **str_disk_guid, | |
0528979f | 429 | struct disk_partition **partitions, |
8b096237 PW |
430 | u8 *parts_count) |
431 | { | |
432 | char *tok, *str, *s; | |
433 | int i; | |
434 | char *val, *p; | |
435 | int p_count; | |
0528979f | 436 | struct disk_partition *parts; |
8b096237 | 437 | int errno = 0; |
3e34cf7b | 438 | uint64_t size_ll, start_ll; |
66636235 | 439 | lbaint_t offset = 0; |
2fcaa413 | 440 | int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS); |
8b096237 | 441 | |
619f0fdf | 442 | debug("%s: lba num: 0x%x %d\n", __func__, |
8b096237 PW |
443 | (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); |
444 | ||
445 | if (str_part == NULL) | |
446 | return -1; | |
447 | ||
448 | str = strdup(str_part); | |
203f9b48 AC |
449 | if (str == NULL) |
450 | return -ENOMEM; | |
8b096237 PW |
451 | |
452 | /* extract disk guid */ | |
453 | s = str; | |
0c7e8d13 | 454 | val = extract_val(str, "uuid_disk"); |
8b096237 | 455 | if (!val) { |
0c7e8d13 RH |
456 | #ifdef CONFIG_RANDOM_UUID |
457 | *str_disk_guid = malloc(UUID_STR_LEN + 1); | |
bf52fcde | 458 | if (*str_disk_guid == NULL) |
2fcaa413 | 459 | return -ENOMEM; |
0c7e8d13 RH |
460 | gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD); |
461 | #else | |
8b096237 PW |
462 | free(str); |
463 | return -2; | |
0c7e8d13 RH |
464 | #endif |
465 | } else { | |
466 | val = strsep(&val, ";"); | |
467 | if (extract_env(val, &p)) | |
468 | p = val; | |
469 | *str_disk_guid = strdup(p); | |
470 | free(val); | |
471 | /* Move s to first partition */ | |
472 | strsep(&s, ";"); | |
8b096237 | 473 | } |
2fcaa413 AC |
474 | if (s == NULL) { |
475 | printf("Error: is the partitions string NULL-terminated?\n"); | |
476 | return -EINVAL; | |
477 | } | |
478 | if (strnlen(s, max_str_part) == 0) | |
8b096237 PW |
479 | return -3; |
480 | ||
2fcaa413 | 481 | i = strnlen(s, max_str_part) - 1; |
8b096237 PW |
482 | if (s[i] == ';') |
483 | s[i] = '\0'; | |
484 | ||
485 | /* calculate expected number of partitions */ | |
486 | p_count = 1; | |
487 | p = s; | |
488 | while (*p) { | |
489 | if (*p++ == ';') | |
490 | p_count++; | |
491 | } | |
492 | ||
493 | /* allocate memory for partitions */ | |
0528979f | 494 | parts = calloc(sizeof(struct disk_partition), p_count); |
2fcaa413 AC |
495 | if (parts == NULL) |
496 | return -ENOMEM; | |
8b096237 | 497 | |
1f8b546f | 498 | /* retrieve partitions data from string */ |
8b096237 PW |
499 | for (i = 0; i < p_count; i++) { |
500 | tok = strsep(&s, ";"); | |
501 | ||
502 | if (tok == NULL) | |
503 | break; | |
504 | ||
505 | /* uuid */ | |
506 | val = extract_val(tok, "uuid"); | |
0c7e8d13 RH |
507 | if (!val) { |
508 | /* 'uuid' is optional if random uuid's are enabled */ | |
509 | #ifdef CONFIG_RANDOM_UUID | |
510 | gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD); | |
511 | #else | |
8b096237 PW |
512 | errno = -4; |
513 | goto err; | |
0c7e8d13 RH |
514 | #endif |
515 | } else { | |
516 | if (extract_env(val, &p)) | |
517 | p = val; | |
2fcaa413 | 518 | if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) { |
0c7e8d13 RH |
519 | printf("Wrong uuid format for partition %d\n", i); |
520 | errno = -4; | |
521 | goto err; | |
522 | } | |
2fcaa413 | 523 | strncpy((char *)parts[i].uuid, p, max_str_part); |
0c7e8d13 | 524 | free(val); |
8b096237 | 525 | } |
7561b258 PD |
526 | #ifdef CONFIG_PARTITION_TYPE_GUID |
527 | /* guid */ | |
528 | val = extract_val(tok, "type"); | |
529 | if (val) { | |
530 | /* 'type' is optional */ | |
531 | if (extract_env(val, &p)) | |
532 | p = val; | |
2fcaa413 | 533 | if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) { |
7561b258 PD |
534 | printf("Wrong type guid format for partition %d\n", |
535 | i); | |
536 | errno = -4; | |
537 | goto err; | |
538 | } | |
2fcaa413 | 539 | strncpy((char *)parts[i].type_guid, p, max_str_part); |
7561b258 PD |
540 | free(val); |
541 | } | |
542 | #endif | |
8b096237 PW |
543 | /* name */ |
544 | val = extract_val(tok, "name"); | |
545 | if (!val) { /* name is mandatory */ | |
546 | errno = -4; | |
547 | goto err; | |
548 | } | |
549 | if (extract_env(val, &p)) | |
550 | p = val; | |
2fcaa413 | 551 | if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) { |
8b096237 PW |
552 | errno = -4; |
553 | goto err; | |
554 | } | |
2fcaa413 | 555 | strncpy((char *)parts[i].name, p, max_str_part); |
8b096237 PW |
556 | free(val); |
557 | ||
558 | /* size */ | |
559 | val = extract_val(tok, "size"); | |
560 | if (!val) { /* 'size' is mandatory */ | |
561 | errno = -4; | |
562 | goto err; | |
563 | } | |
564 | if (extract_env(val, &p)) | |
565 | p = val; | |
66636235 | 566 | if ((strcmp(p, "-") == 0)) { |
c2fdd345 KY |
567 | /* Let part efi module to auto extend the size */ |
568 | parts[i].size = 0; | |
66636235 MT |
569 | } else { |
570 | size_ll = ustrtoull(p, &p, 0); | |
571 | parts[i].size = lldiv(size_ll, dev_desc->blksz); | |
572 | } | |
573 | ||
8b096237 PW |
574 | free(val); |
575 | ||
576 | /* start address */ | |
577 | val = extract_val(tok, "start"); | |
578 | if (val) { /* start address is optional */ | |
579 | if (extract_env(val, &p)) | |
580 | p = val; | |
3e34cf7b PW |
581 | start_ll = ustrtoull(p, &p, 0); |
582 | parts[i].start = lldiv(start_ll, dev_desc->blksz); | |
8b096237 PW |
583 | free(val); |
584 | } | |
cfdaf4ca | 585 | |
66636235 MT |
586 | offset += parts[i].size + parts[i].start; |
587 | ||
cfdaf4ca PD |
588 | /* bootable */ |
589 | if (found_key(tok, "bootable")) | |
25801acc | 590 | parts[i].bootable = PART_BOOTABLE; |
8b096237 PW |
591 | } |
592 | ||
593 | *parts_count = p_count; | |
594 | *partitions = parts; | |
595 | free(str); | |
596 | ||
597 | return 0; | |
598 | err: | |
599 | free(str); | |
600 | free(*str_disk_guid); | |
601 | free(parts); | |
602 | ||
603 | return errno; | |
604 | } | |
605 | ||
26f404c7 PR |
606 | static int gpt_repair(struct blk_desc *blk_dev_desc) |
607 | { | |
608 | int ret = 0; | |
609 | ||
610 | ret = gpt_repair_headers(blk_dev_desc); | |
611 | ||
612 | return ret; | |
613 | } | |
614 | ||
4101f687 | 615 | static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) |
8b096237 PW |
616 | { |
617 | int ret; | |
618 | char *str_disk_guid; | |
619 | u8 part_count = 0; | |
0528979f | 620 | struct disk_partition *partitions = NULL; |
8b096237 | 621 | |
8b096237 | 622 | /* fill partitions */ |
619f0fdf | 623 | ret = set_gpt_info(blk_dev_desc, str_part, |
8b096237 PW |
624 | &str_disk_guid, &partitions, &part_count); |
625 | if (ret) { | |
626 | if (ret == -1) | |
627 | printf("No partition list provided\n"); | |
628 | if (ret == -2) | |
629 | printf("Missing disk guid\n"); | |
630 | if ((ret == -3) || (ret == -4)) | |
631 | printf("Partition list incomplete\n"); | |
632 | return -1; | |
633 | } | |
634 | ||
635 | /* save partitions layout to disk */ | |
a150e6c9 | 636 | ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count); |
8b096237 PW |
637 | free(str_disk_guid); |
638 | free(partitions); | |
639 | ||
a150e6c9 | 640 | return ret; |
8b096237 PW |
641 | } |
642 | ||
4101f687 | 643 | static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) |
bbb9ffac LM |
644 | { |
645 | ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, | |
646 | blk_dev_desc->blksz); | |
0528979f | 647 | struct disk_partition *partitions = NULL; |
bbb9ffac LM |
648 | gpt_entry *gpt_pte = NULL; |
649 | char *str_disk_guid; | |
650 | u8 part_count = 0; | |
651 | int ret = 0; | |
652 | ||
653 | /* fill partitions */ | |
654 | ret = set_gpt_info(blk_dev_desc, str_part, | |
655 | &str_disk_guid, &partitions, &part_count); | |
656 | if (ret) { | |
657 | if (ret == -1) { | |
658 | printf("No partition list provided - only basic check\n"); | |
659 | ret = gpt_verify_headers(blk_dev_desc, gpt_head, | |
660 | &gpt_pte); | |
661 | goto out; | |
662 | } | |
663 | if (ret == -2) | |
664 | printf("Missing disk guid\n"); | |
665 | if ((ret == -3) || (ret == -4)) | |
666 | printf("Partition list incomplete\n"); | |
667 | return -1; | |
668 | } | |
669 | ||
670 | /* Check partition layout with provided pattern */ | |
671 | ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count, | |
672 | gpt_head, &gpt_pte); | |
673 | free(str_disk_guid); | |
674 | free(partitions); | |
675 | out: | |
676 | free(gpt_pte); | |
677 | return ret; | |
678 | } | |
679 | ||
12fc1f3b CD |
680 | /** |
681 | * gpt_enumerate() - Enumerate partition names into environment variable. | |
682 | * | |
683 | * Enumerate partition names. Partition names are stored in gpt_partition_list | |
684 | * environment variable. Each partition name is delimited by space. | |
685 | * | |
686 | * @desc: block device descriptor | |
687 | * | |
688 | * @Return: '0' on success and -ve error on failure | |
689 | */ | |
690 | static int gpt_enumerate(struct blk_desc *desc) | |
691 | { | |
692 | struct part_driver *first_drv, *part_drv; | |
693 | int str_len = 0, tmp_len; | |
694 | char part_list[2048]; | |
695 | int n_drvs; | |
696 | char *ptr; | |
697 | ||
698 | part_list[0] = 0; | |
699 | n_drvs = part_driver_get_count(); | |
700 | if (!n_drvs) { | |
701 | printf("Failed to get partition driver count\n"); | |
702 | return -ENOENT; | |
703 | } | |
704 | ||
705 | first_drv = part_driver_get_first(); | |
706 | for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) { | |
707 | struct disk_partition pinfo; | |
708 | int ret; | |
709 | int i; | |
710 | ||
41cd23b7 HS |
711 | if (part_drv->test(desc)) |
712 | continue; | |
713 | ||
12fc1f3b CD |
714 | for (i = 1; i < part_drv->max_entries; i++) { |
715 | ret = part_drv->get_info(desc, i, &pinfo); | |
41cd23b7 HS |
716 | if (ret) |
717 | continue; | |
12fc1f3b CD |
718 | |
719 | ptr = &part_list[str_len]; | |
720 | tmp_len = strlen((const char *)pinfo.name); | |
721 | str_len += tmp_len; | |
722 | /* +1 for space */ | |
723 | str_len++; | |
724 | if (str_len > sizeof(part_list)) { | |
725 | printf("Error insufficient memory\n"); | |
726 | return -ENOMEM; | |
727 | } | |
728 | strcpy(ptr, (const char *)pinfo.name); | |
729 | /* One byte for space(" ") delimiter */ | |
730 | ptr[tmp_len] = ' '; | |
731 | } | |
41cd23b7 HS |
732 | if (*part_list) |
733 | part_list[strlen(part_list) - 1] = 0; | |
734 | break; | |
12fc1f3b | 735 | } |
12fc1f3b CD |
736 | debug("setenv gpt_partition_list %s\n", part_list); |
737 | ||
738 | return env_set("gpt_partition_list", part_list); | |
739 | } | |
740 | ||
741 | /** | |
742 | * gpt_setenv_part_variables() - setup partition environmental variables | |
743 | * | |
744 | * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr | |
b1433aff | 745 | * and gpt_partition_size, gpt_partition_bootable environment variables. |
12fc1f3b CD |
746 | * |
747 | * @pinfo: pointer to disk partition | |
748 | * @i: partition entry | |
749 | * | |
750 | * @Return: '0' on success and -ENOENT on failure | |
751 | */ | |
752 | static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) | |
753 | { | |
754 | int ret; | |
755 | ||
756 | ret = env_set_hex("gpt_partition_addr", pinfo->start); | |
757 | if (ret) | |
758 | goto fail; | |
759 | ||
760 | ret = env_set_hex("gpt_partition_size", pinfo->size); | |
761 | if (ret) | |
762 | goto fail; | |
763 | ||
eeef5840 | 764 | ret = env_set_hex("gpt_partition_entry", i); |
12fc1f3b CD |
765 | if (ret) |
766 | goto fail; | |
767 | ||
768 | ret = env_set("gpt_partition_name", (const char *)pinfo->name); | |
769 | if (ret) | |
770 | goto fail; | |
771 | ||
b1433aff JW |
772 | ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE)); |
773 | if (ret) | |
774 | goto fail; | |
775 | ||
12fc1f3b CD |
776 | return 0; |
777 | ||
778 | fail: | |
779 | return -ENOENT; | |
780 | } | |
781 | ||
782 | /** | |
783 | * gpt_setenv() - Dynamically setup environment variables. | |
784 | * | |
785 | * Dynamically setup environment variables for name, index, offset and size | |
786 | * for partition in GPT table after running "gpt setenv" for a partition name. | |
787 | * | |
788 | * @desc: block device descriptor | |
789 | * @name: partition name | |
790 | * | |
791 | * @Return: '0' on success and -ve err on failure | |
792 | */ | |
793 | static int gpt_setenv(struct blk_desc *desc, const char *name) | |
794 | { | |
795 | struct part_driver *first_drv, *part_drv; | |
796 | int n_drvs; | |
797 | int ret = -1; | |
798 | ||
799 | n_drvs = part_driver_get_count(); | |
800 | if (!n_drvs) { | |
801 | printf("Failed to get partition driver count\n"); | |
802 | goto fail; | |
803 | } | |
804 | ||
805 | first_drv = part_driver_get_first(); | |
806 | for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) { | |
807 | struct disk_partition pinfo; | |
808 | int i; | |
809 | ||
810 | for (i = 1; i < part_drv->max_entries; i++) { | |
811 | ret = part_drv->get_info(desc, i, &pinfo); | |
01834677 HS |
812 | if (ret) |
813 | continue; | |
12fc1f3b CD |
814 | |
815 | if (!strcmp(name, (const char *)pinfo.name)) { | |
816 | /* match found, setup environment variables */ | |
817 | ret = gpt_setenv_part_variables(&pinfo, i); | |
818 | if (ret) | |
819 | goto fail; | |
820 | ||
821 | return 0; | |
822 | } | |
823 | } | |
824 | } | |
825 | ||
826 | fail: | |
827 | return ret; | |
828 | } | |
829 | ||
73d6d18b AC |
830 | static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr) |
831 | { | |
832 | int ret; | |
833 | char disk_guid[UUID_STR_LEN + 1]; | |
834 | ||
835 | ret = get_disk_guid(dev_desc, disk_guid); | |
836 | if (ret < 0) | |
837 | return CMD_RET_FAILURE; | |
838 | ||
839 | if (namestr) | |
382bee57 | 840 | env_set(namestr, disk_guid); |
73d6d18b AC |
841 | else |
842 | printf("%s\n", disk_guid); | |
843 | ||
844 | return ret; | |
845 | } | |
846 | ||
203f9b48 AC |
847 | #ifdef CONFIG_CMD_GPT_RENAME |
848 | static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, | |
849 | char *name1, char *name2) | |
850 | { | |
851 | struct list_head *pos; | |
852 | struct disk_part *curr; | |
0528979f | 853 | struct disk_partition *new_partitions = NULL; |
203f9b48 | 854 | char disk_guid[UUID_STR_LEN + 1]; |
5749faa3 | 855 | char *partitions_list, *str_disk_guid = NULL; |
203f9b48 AC |
856 | u8 part_count = 0; |
857 | int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0; | |
858 | ||
859 | if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || | |
860 | (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) | |
861 | return -EINVAL; | |
862 | ||
863 | ret = get_disk_guid(dev_desc, disk_guid); | |
864 | if (ret < 0) | |
865 | return ret; | |
18030d04 AC |
866 | /* |
867 | * Allocates disk_partitions, requiring matching call to del_gpt_info() | |
868 | * if successful. | |
869 | */ | |
203f9b48 AC |
870 | numparts = get_gpt_info(dev_desc); |
871 | if (numparts <= 0) | |
872 | return numparts ? numparts : -ENODEV; | |
873 | ||
874 | partlistlen = calc_parts_list_len(numparts); | |
875 | partitions_list = malloc(partlistlen); | |
18030d04 AC |
876 | if (!partitions_list) { |
877 | del_gpt_info(); | |
203f9b48 | 878 | return -ENOMEM; |
18030d04 | 879 | } |
203f9b48 AC |
880 | memset(partitions_list, '\0', partlistlen); |
881 | ||
882 | ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list); | |
18030d04 AC |
883 | if (ret < 0) { |
884 | free(partitions_list); | |
203f9b48 | 885 | return ret; |
18030d04 | 886 | } |
203f9b48 AC |
887 | /* |
888 | * Uncomment the following line to print a string that 'gpt write' | |
889 | * or 'gpt verify' will accept as input. | |
890 | */ | |
891 | debug("OLD partitions_list is %s with %u chars\n", partitions_list, | |
892 | (unsigned)strlen(partitions_list)); | |
893 | ||
18030d04 | 894 | /* set_gpt_info allocates new_partitions and str_disk_guid */ |
203f9b48 AC |
895 | ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid, |
896 | &new_partitions, &part_count); | |
5749faa3 TR |
897 | if (ret < 0) |
898 | goto out; | |
203f9b48 AC |
899 | |
900 | if (!strcmp(subcomm, "swap")) { | |
901 | if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) { | |
902 | printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); | |
18030d04 AC |
903 | ret = -EINVAL; |
904 | goto out; | |
203f9b48 AC |
905 | } |
906 | list_for_each(pos, &disk_partitions) { | |
907 | curr = list_entry(pos, struct disk_part, list); | |
908 | if (!strcmp((char *)curr->gpt_part_info.name, name1)) { | |
909 | strcpy((char *)curr->gpt_part_info.name, name2); | |
910 | ctr1++; | |
911 | } else if (!strcmp((char *)curr->gpt_part_info.name, name2)) { | |
912 | strcpy((char *)curr->gpt_part_info.name, name1); | |
913 | ctr2++; | |
914 | } | |
915 | } | |
916 | if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) { | |
917 | printf("Cannot swap partition names except in pairs.\n"); | |
18030d04 AC |
918 | ret = -EINVAL; |
919 | goto out; | |
203f9b48 AC |
920 | } |
921 | } else { /* rename */ | |
922 | if (strlen(name2) > PART_NAME_LEN) { | |
923 | printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); | |
18030d04 AC |
924 | ret = -EINVAL; |
925 | goto out; | |
203f9b48 AC |
926 | } |
927 | partnum = (int)simple_strtol(name1, NULL, 10); | |
928 | if ((partnum < 0) || (partnum > numparts)) { | |
929 | printf("Illegal partition number %s\n", name1); | |
18030d04 AC |
930 | ret = -EINVAL; |
931 | goto out; | |
203f9b48 AC |
932 | } |
933 | ret = part_get_info(dev_desc, partnum, new_partitions); | |
934 | if (ret < 0) | |
18030d04 | 935 | goto out; |
203f9b48 AC |
936 | |
937 | /* U-Boot partition numbering starts at 1 */ | |
938 | list_for_each(pos, &disk_partitions) { | |
939 | curr = list_entry(pos, struct disk_part, list); | |
940 | if (i == partnum) { | |
941 | strcpy((char *)curr->gpt_part_info.name, name2); | |
942 | break; | |
943 | } | |
944 | i++; | |
945 | } | |
946 | } | |
947 | ||
948 | ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list); | |
949 | if (ret < 0) | |
18030d04 | 950 | goto out; |
203f9b48 AC |
951 | debug("NEW partitions_list is %s with %u chars\n", partitions_list, |
952 | (unsigned)strlen(partitions_list)); | |
953 | ||
954 | ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid, | |
955 | &new_partitions, &part_count); | |
18030d04 AC |
956 | /* |
957 | * Even though valid pointers are here passed into set_gpt_info(), | |
958 | * it mallocs again, and there's no way to tell which failed. | |
959 | */ | |
5749faa3 TR |
960 | if (ret < 0) |
961 | goto out; | |
203f9b48 AC |
962 | |
963 | debug("Writing new partition table\n"); | |
964 | ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts); | |
965 | if (ret < 0) { | |
966 | printf("Writing new partition table failed\n"); | |
18030d04 | 967 | goto out; |
203f9b48 AC |
968 | } |
969 | ||
970 | debug("Reading back new partition table\n"); | |
18030d04 AC |
971 | /* |
972 | * Empty the existing disk_partitions list, as otherwise the memory in | |
973 | * the original list is unreachable. | |
974 | */ | |
975 | del_gpt_info(); | |
203f9b48 | 976 | numparts = get_gpt_info(dev_desc); |
18030d04 AC |
977 | if (numparts <= 0) { |
978 | ret = numparts ? numparts : -ENODEV; | |
979 | goto out; | |
980 | } | |
203f9b48 AC |
981 | printf("new partition table with %d partitions is:\n", numparts); |
982 | print_gpt_info(); | |
18030d04 | 983 | out: |
5749faa3 TR |
984 | del_gpt_info(); |
985 | #ifdef CONFIG_RANDOM_UUID | |
b142d0ac | 986 | free(str_disk_guid); |
5749faa3 | 987 | #endif |
b142d0ac | 988 | free(new_partitions); |
18030d04 | 989 | free(partitions_list); |
203f9b48 AC |
990 | return ret; |
991 | } | |
a1e793ad JW |
992 | |
993 | /** | |
994 | * gpt_set_bootable() - Set bootable flags for partitions | |
995 | * | |
996 | * Sets the bootable flag for any partition names in the comma separated list of | |
997 | * partition names. Any partitions not in the list have their bootable flag | |
998 | * cleared | |
999 | * | |
1000 | * @desc: block device descriptor | |
1001 | * @name: Comma separated list of partition names | |
1002 | * | |
1003 | * @Return: '0' on success and -ve error on failure | |
1004 | */ | |
1005 | static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) | |
1006 | { | |
1007 | char *name; | |
1008 | char disk_guid[UUID_STR_LEN + 1]; | |
1009 | struct list_head *pos; | |
1010 | struct disk_part *curr; | |
1011 | struct disk_partition *partitions = NULL; | |
1012 | int part_count = 0; | |
1013 | int ret = get_disk_guid(blk_dev_desc, disk_guid); | |
1014 | ||
1015 | if (ret < 0) | |
1016 | return ret; | |
1017 | ||
1018 | ret = get_gpt_info(blk_dev_desc); | |
1019 | if (ret <= 0) | |
1020 | goto out; | |
1021 | ||
1022 | part_count = ret; | |
1023 | partitions = malloc(sizeof(*partitions) * part_count); | |
1024 | if (!partitions) { | |
1025 | ret = -ENOMEM; | |
1026 | goto out; | |
1027 | } | |
1028 | ||
1029 | /* Copy partitions and clear bootable flag */ | |
1030 | part_count = 0; | |
1031 | list_for_each(pos, &disk_partitions) { | |
1032 | curr = list_entry(pos, struct disk_part, list); | |
1033 | partitions[part_count] = curr->gpt_part_info; | |
1034 | partitions[part_count].bootable &= ~PART_BOOTABLE; | |
1035 | part_count++; | |
1036 | } | |
1037 | ||
1038 | name = strtok(part_list, ","); | |
1039 | while (name) { | |
1040 | bool found = false; | |
1041 | ||
1042 | for (int i = 0; i < part_count; i++) { | |
1043 | if (strcmp((char *)partitions[i].name, name) == 0) { | |
1044 | partitions[i].bootable |= PART_BOOTABLE; | |
1045 | found = true; | |
1046 | } | |
1047 | } | |
1048 | ||
1049 | if (!found) { | |
1050 | printf("Warning: No partition matching '%s' found\n", | |
1051 | name); | |
1052 | } | |
1053 | ||
1054 | name = strtok(NULL, ","); | |
1055 | } | |
1056 | ||
1057 | ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count); | |
1058 | ||
1059 | out: | |
1060 | del_gpt_info(); | |
1061 | ||
1062 | if (partitions) | |
1063 | free(partitions); | |
1064 | ||
1065 | return ret; | |
1066 | } | |
203f9b48 AC |
1067 | #endif |
1068 | ||
8b096237 PW |
1069 | /** |
1070 | * do_gpt(): Perform GPT operations | |
1071 | * | |
1072 | * @param cmdtp - command name | |
1073 | * @param flag | |
1074 | * @param argc | |
1075 | * @param argv | |
1076 | * | |
185f812c | 1077 | * Return: zero on success; otherwise error |
8b096237 | 1078 | */ |
09140113 | 1079 | static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
8b096237 PW |
1080 | { |
1081 | int ret = CMD_RET_SUCCESS; | |
1082 | int dev = 0; | |
619f0fdf | 1083 | char *ep; |
4101f687 | 1084 | struct blk_desc *blk_dev_desc = NULL; |
8b096237 | 1085 | |
203f9b48 | 1086 | #ifndef CONFIG_CMD_GPT_RENAME |
bbb9ffac | 1087 | if (argc < 4 || argc > 5) |
203f9b48 AC |
1088 | #else |
1089 | if (argc < 4 || argc > 6) | |
1090 | #endif | |
8b096237 PW |
1091 | return CMD_RET_USAGE; |
1092 | ||
0b1284eb | 1093 | dev = (int)dectoul(argv[3], &ep); |
bbb9ffac LM |
1094 | if (!ep || ep[0] != '\0') { |
1095 | printf("'%s' is not a number\n", argv[3]); | |
1096 | return CMD_RET_USAGE; | |
1097 | } | |
db1d9e78 | 1098 | blk_dev_desc = blk_get_dev(argv[2], dev); |
bbb9ffac LM |
1099 | if (!blk_dev_desc) { |
1100 | printf("%s: %s dev %d NOT available\n", | |
1101 | __func__, argv[2], dev); | |
1102 | return CMD_RET_FAILURE; | |
1103 | } | |
39206382 | 1104 | |
26f404c7 PR |
1105 | if (strcmp(argv[1], "repair") == 0) { |
1106 | printf("Repairing GPT: "); | |
1107 | ret = gpt_repair(blk_dev_desc); | |
1108 | } else if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { | |
bbb9ffac | 1109 | printf("Writing GPT: "); |
39206382 | 1110 | ret = gpt_default(blk_dev_desc, argv[4]); |
bbb9ffac LM |
1111 | } else if ((strcmp(argv[1], "verify") == 0)) { |
1112 | ret = gpt_verify(blk_dev_desc, argv[4]); | |
1113 | printf("Verify GPT: "); | |
12fc1f3b CD |
1114 | } else if ((strcmp(argv[1], "setenv") == 0)) { |
1115 | ret = gpt_setenv(blk_dev_desc, argv[4]); | |
1116 | } else if ((strcmp(argv[1], "enumerate") == 0)) { | |
1117 | ret = gpt_enumerate(blk_dev_desc); | |
73d6d18b AC |
1118 | } else if (strcmp(argv[1], "guid") == 0) { |
1119 | ret = do_disk_guid(blk_dev_desc, argv[4]); | |
09a49930 AC |
1120 | #ifdef CONFIG_CMD_GPT_RENAME |
1121 | } else if (strcmp(argv[1], "read") == 0) { | |
653cd92d | 1122 | ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); |
203f9b48 AC |
1123 | } else if ((strcmp(argv[1], "swap") == 0) || |
1124 | (strcmp(argv[1], "rename") == 0)) { | |
1125 | ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); | |
a1e793ad JW |
1126 | } else if ((strcmp(argv[1], "set-bootable") == 0)) { |
1127 | ret = gpt_set_bootable(blk_dev_desc, argv[4]); | |
09a49930 | 1128 | #endif |
8b096237 PW |
1129 | } else { |
1130 | return CMD_RET_USAGE; | |
1131 | } | |
bbb9ffac LM |
1132 | |
1133 | if (ret) { | |
1134 | printf("error!\n"); | |
1135 | return CMD_RET_FAILURE; | |
1136 | } | |
1137 | ||
1138 | printf("success!\n"); | |
1139 | return CMD_RET_SUCCESS; | |
8b096237 PW |
1140 | } |
1141 | ||
1142 | U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, | |
1143 | "GUID Partition Table", | |
1f8b546f | 1144 | "<command> <interface> <dev> <partitions_list>\n" |
74f889b0 LM |
1145 | " - GUID partition table restoration and validity check\n" |
1146 | " Restore or verify GPT information on a device connected\n" | |
8b096237 | 1147 | " to interface\n" |
74f889b0 | 1148 | " Example usage:\n" |
26f404c7 PR |
1149 | " gpt repair mmc 0\n" |
1150 | " - repair the GPT on the device\n" | |
74f889b0 | 1151 | " gpt write mmc 0 $partitions\n" |
12fc1f3b | 1152 | " - write the GPT to device\n" |
74f889b0 | 1153 | " gpt verify mmc 0 $partitions\n" |
12fc1f3b CD |
1154 | " - verify the GPT on device against $partitions\n" |
1155 | " gpt setenv mmc 0 $name\n" | |
1156 | " - setup environment variables for partition $name:\n" | |
1157 | " gpt_partition_addr, gpt_partition_size,\n" | |
b1433aff JW |
1158 | " gpt_partition_name, gpt_partition_entry,\n" |
1159 | " gpt_partition_bootable\n" | |
12fc1f3b CD |
1160 | " gpt enumerate mmc 0\n" |
1161 | " - store list of partitions to gpt_partition_list environment variable\n" | |
d0266096 | 1162 | " gpt guid <interface> <dev>\n" |
73d6d18b | 1163 | " - print disk GUID\n" |
d0266096 | 1164 | " gpt guid <interface> <dev> <varname>\n" |
73d6d18b AC |
1165 | " - set environment variable to disk GUID\n" |
1166 | " Example usage:\n" | |
1167 | " gpt guid mmc 0\n" | |
1168 | " gpt guid mmc 0 varname\n" | |
203f9b48 AC |
1169 | #ifdef CONFIG_CMD_GPT_RENAME |
1170 | "gpt partition renaming commands:\n" | |
653cd92d | 1171 | " gpt read <interface> <dev> [<varname>]\n" |
d0266096 | 1172 | " - read GPT into a data structure for manipulation\n" |
653cd92d | 1173 | " - read GPT partitions into environment variable\n" |
d0266096 | 1174 | " gpt swap <interface> <dev> <name1> <name2>\n" |
203f9b48 AC |
1175 | " - change all partitions named name1 to name2\n" |
1176 | " and vice-versa\n" | |
d0266096 | 1177 | " gpt rename <interface> <dev> <part> <name>\n" |
203f9b48 | 1178 | " - rename the specified partition\n" |
a1e793ad JW |
1179 | " gpt set-bootable <interface> <dev> <list>\n" |
1180 | " - make partition names in list bootable\n" | |
203f9b48 AC |
1181 | " Example usage:\n" |
1182 | " gpt swap mmc 0 foo bar\n" | |
1183 | " gpt rename mmc 0 3 foo\n" | |
a1e793ad | 1184 | " gpt set-bootable mmc 0 boot_a,boot_b\n" |
203f9b48 | 1185 | #endif |
8b096237 | 1186 | ); |