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