Blame view

cmd/gpt.c 21.8 KB
8b0962376   Piotr Wilczek   gpt: Support for ...
1
2
3
  /*
   * cmd_gpt.c -- GPT (GUID Partition Table) handling command
   *
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
4
5
6
   * Copyright (C) 2015
   * Lukasz Majewski <l.majewski@majess.pl>
   *
8b0962376   Piotr Wilczek   gpt: Support for ...
7
8
9
10
   * Copyright (C) 2012 Samsung Electronics
   * author: Lukasz Majewski <l.majewski@samsung.com>
   * author: Piotr Wilczek <p.wilczek@samsung.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
11
   * SPDX-License-Identifier:	GPL-2.0+
8b0962376   Piotr Wilczek   gpt: Support for ...
12
13
14
15
16
   */
  
  #include <common.h>
  #include <malloc.h>
  #include <command.h>
8b0962376   Piotr Wilczek   gpt: Support for ...
17
18
19
  #include <part_efi.h>
  #include <exports.h>
  #include <linux/ctype.h>
3e34cf7bf   Piotr Wilczek   gpt: fix partion ...
20
  #include <div64.h>
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
21
  #include <memalign.h>
09a49930e   Alison Chaiken   GPT: read partiti...
22
  #include <linux/compat.h>
203f9b48a   Alison Chaiken   GPT: provide comm...
23
24
  #include <linux/sizes.h>
  #include <stdlib.h>
09a49930e   Alison Chaiken   GPT: read partiti...
25
26
  
  static LIST_HEAD(disk_partitions);
8b0962376   Piotr Wilczek   gpt: Support for ...
27

8b0962376   Piotr Wilczek   gpt: Support for ...
28
29
30
31
32
33
34
35
36
  /**
   * extract_env(): Expand env name from string format '&{env_name}'
   *                and return pointer to the env (if the env is set)
   *
   * @param str - pointer to string
   * @param env - pointer to pointer to extracted env
   *
   * @return - zero on successful expand and env is set
   */
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
37
  static int extract_env(const char *str, char **env)
8b0962376   Piotr Wilczek   gpt: Support for ...
38
  {
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
39
  	int ret = -1;
8b0962376   Piotr Wilczek   gpt: Support for ...
40
  	char *e, *s;
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
41
42
43
  #ifdef CONFIG_RANDOM_UUID
  	char uuid_str[UUID_STR_LEN + 1];
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
44
45
46
  
  	if (!str || strlen(str) < 4)
  		return -1;
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
47
48
49
50
51
52
53
54
55
  	if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')))
  		return -1;
  
  	s = strdup(str);
  	if (s == NULL)
  		return -1;
  
  	memset(s + strlen(s) - 1, '\0', 1);
  	memmove(s, s + 2, strlen(s) - 1);
00caae6d4   Simon Glass   env: Rename geten...
56
  	e = env_get(s);
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
57
58
59
  	if (e == NULL) {
  #ifdef CONFIG_RANDOM_UUID
  		debug("%s unset. ", str);
9da52f8f6   Vincent Tinelli   gpt: Fix uuid str...
60
  		gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID);
382bee57f   Simon Glass   env: Rename seten...
61
  		env_set(s, uuid_str);
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
62

00caae6d4   Simon Glass   env: Rename geten...
63
  		e = env_get(s);
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
64
65
66
67
68
69
70
  		if (e) {
  			debug("Set to random.
  ");
  			ret = 0;
  		} else {
  			debug("Can't get random UUID.
  ");
8b0962376   Piotr Wilczek   gpt: Support for ...
71
  		}
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
72
73
74
75
76
77
78
79
  #else
  		debug("%s unset.
  ", str);
  #endif
  	} else {
  		debug("%s get from environment.
  ", str);
  		ret = 0;
8b0962376   Piotr Wilczek   gpt: Support for ...
80
  	}
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
81
82
83
84
  	*env = e;
  	free(s);
  
  	return ret;
8b0962376   Piotr Wilczek   gpt: Support for ...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  }
  
  /**
   * extract_val(): Extract value from a key=value pair list (comma separated).
   *                Only value for the given key is returend.
   *                Function allocates memory for the value, remember to free!
   *
   * @param str - pointer to string with key=values pairs
   * @param key - pointer to the key to search for
   *
   * @return - pointer to allocated string with the value
   */
  static char *extract_val(const char *str, const char *key)
  {
  	char *v, *k;
  	char *s, *strcopy;
  	char *new = NULL;
  
  	strcopy = strdup(str);
  	if (strcopy == NULL)
  		return NULL;
  
  	s = strcopy;
  	while (s) {
  		v = strsep(&s, ",");
  		if (!v)
  			break;
  		k = strsep(&v, "=");
  		if (!k)
  			break;
  		if  (strcmp(k, key) == 0) {
  			new = strdup(v);
  			break;
  		}
  	}
  
  	free(strcopy);
  
  	return new;
  }
  
  /**
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
   * found_key(): Found key without value in parameter list (comma separated).
   *
   * @param str - pointer to string with key
   * @param key - pointer to the key to search for
   *
   * @return - true on found key
   */
  static bool found_key(const char *str, const char *key)
  {
  	char *k;
  	char *s, *strcopy;
  	bool result = false;
  
  	strcopy = strdup(str);
  	if (!strcopy)
  		return NULL;
  
  	s = strcopy;
  	while (s) {
  		k = strsep(&s, ",");
  		if (!k)
  			break;
  		if  (strcmp(k, key) == 0) {
  			result = true;
  			break;
  		}
  	}
  
  	free(strcopy);
  
  	return result;
  }
2fcaa413b   Alison Chaiken   gpt: harden set_g...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  static int calc_parts_list_len(int numparts)
  {
  	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
  	/* for the comma */
  	partlistlen++;
  
  	/* per-partition additions; numparts starts at 1, so this should be correct */
  	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
  	/* see part.h for definition of struct disk_partition */
  	partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1);
  	partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1);
  	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
  	/* for the terminating null */
  	partlistlen++;
  	debug("Length of partitions_list is %d for %d partitions
  ", partlistlen,
  	      numparts);
  	return partlistlen;
  }
09a49930e   Alison Chaiken   GPT: read partiti...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  #ifdef CONFIG_CMD_GPT_RENAME
  static void del_gpt_info(void)
  {
  	struct list_head *pos = &disk_partitions;
  	struct disk_part *curr;
  	while (!list_empty(pos)) {
  		curr = list_entry(pos->next, struct disk_part, list);
  		list_del(pos->next);
  		free(curr);
  	}
  }
  
  static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
  {
  	struct disk_part *newpart;
f66bc0e0b   Heinrich Schuchardt   GPT: incomplete i...
193
  	newpart = calloc(1, sizeof(struct disk_part));
09a49930e   Alison Chaiken   GPT: read partiti...
194
195
  	if (!newpart)
  		return ERR_PTR(-ENOMEM);
09a49930e   Alison Chaiken   GPT: read partiti...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  
  	newpart->gpt_part_info.start = info->start;
  	newpart->gpt_part_info.size = info->size;
  	newpart->gpt_part_info.blksz = info->blksz;
  	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
  		PART_NAME_LEN);
  	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
  	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
  		PART_TYPE_LEN);
  	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
  	newpart->gpt_part_info.bootable = info->bootable;
  #ifdef CONFIG_PARTITION_UUIDS
  	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
  		UUID_STR_LEN);
  	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
  	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
  #endif
  	newpart->partnum = partnum;
  
  	return newpart;
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
217
218
219
220
221
222
223
224
225
  static void prettyprint_part_size(char *sizestr, lbaint_t partsize,
  				  lbaint_t blksize)
  {
  	unsigned long long partbytes, partmegabytes;
  
  	partbytes = partsize * blksize;
  	partmegabytes = lldiv(partbytes, SZ_1M);
  	snprintf(sizestr, 16, "%lluMiB", partmegabytes);
  }
09a49930e   Alison Chaiken   GPT: read partiti...
226
227
228
229
  static void print_gpt_info(void)
  {
  	struct list_head *pos;
  	struct disk_part *curr;
203f9b48a   Alison Chaiken   GPT: provide comm...
230
231
  	char partstartstr[16];
  	char partsizestr[16];
09a49930e   Alison Chaiken   GPT: read partiti...
232
233
234
  
  	list_for_each(pos, &disk_partitions) {
  		curr = list_entry(pos, struct disk_part, list);
203f9b48a   Alison Chaiken   GPT: provide comm...
235
236
237
238
  		prettyprint_part_size(partstartstr, curr->gpt_part_info.start,
  				      curr->gpt_part_info.blksz);
  		prettyprint_part_size(partsizestr, curr->gpt_part_info.size,
  				      curr->gpt_part_info.blksz);
09a49930e   Alison Chaiken   GPT: read partiti...
239
240
  		printf("Partition %d:
  ", curr->partnum);
203f9b48a   Alison Chaiken   GPT: provide comm...
241
242
  		printf("Start %s, size %s
  ", partstartstr, partsizestr);
09a49930e   Alison Chaiken   GPT: read partiti...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  		printf("Block size %lu, name %s
  ", curr->gpt_part_info.blksz,
  		       curr->gpt_part_info.name);
  		printf("Type %s, bootable %d
  ", curr->gpt_part_info.type,
  		       curr->gpt_part_info.bootable);
  #ifdef CONFIG_PARTITION_UUIDS
  		printf("UUID %s
  ", curr->gpt_part_info.uuid);
  #endif
  		printf("
  ");
  	}
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  /*
   * create the string that upstream 'gpt write' command will accept as an
   * argument
   *
   * From doc/README.gpt, Format of partitions layout:
   *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
   *	name=kernel,size=60MiB,uuid=...;"
   * The fields 'name' and 'size' are mandatory for every partition.
   * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
   * are optional if CONFIG_RANDOM_UUID is enabled.
   */
  static int create_gpt_partitions_list(int numparts, const char *guid,
  				      char *partitions_list)
  {
  	struct list_head *pos;
  	struct disk_part *curr;
  	char partstr[PART_NAME_LEN + 1];
  
  	if (!partitions_list)
  		return -EINVAL;
  
  	strcpy(partitions_list, "uuid_disk=");
  	strncat(partitions_list, guid, UUID_STR_LEN + 1);
  	strcat(partitions_list, ";");
  
  	list_for_each(pos, &disk_partitions) {
  		curr = list_entry(pos, struct disk_part, list);
  		strcat(partitions_list, "name=");
  		strncat(partitions_list, (const char *)curr->gpt_part_info.name,
  			PART_NAME_LEN + 1);
3a2605fa8   Patrick Delaunay   cmd: gpt: solve i...
287
288
289
  		sprintf(partstr, ",start=0x%llx",
  			(unsigned long long)curr->gpt_part_info.start *
  					    curr->gpt_part_info.blksz);
203f9b48a   Alison Chaiken   GPT: provide comm...
290
291
  		/* one extra byte for NULL */
  		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
3a2605fa8   Patrick Delaunay   cmd: gpt: solve i...
292
293
294
  		sprintf(partstr, ",size=0x%llx",
  			(unsigned long long)curr->gpt_part_info.size *
  					    curr->gpt_part_info.blksz);
203f9b48a   Alison Chaiken   GPT: provide comm...
295
296
297
298
299
300
301
302
303
  		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
  
  		strcat(partitions_list, ",uuid=");
  		strncat(partitions_list, curr->gpt_part_info.uuid,
  			UUID_STR_LEN + 1);
  		strcat(partitions_list, ";");
  	}
  	return 0;
  }
09a49930e   Alison Chaiken   GPT: read partiti...
304
305
306
307
308
309
310
311
312
313
  /*
   * read partition info into disk_partitions list where
   * it can be printed or modified
   */
  static int get_gpt_info(struct blk_desc *dev_desc)
  {
  	/* start partition numbering at 1, as U-Boot does */
  	int valid_parts = 0, p, ret;
  	disk_partition_t info;
  	struct disk_part *new_disk_part;
203f9b48a   Alison Chaiken   GPT: provide comm...
314
315
316
317
318
  	/*
  	 * Always re-read partition info from device, in case
  	 * it has changed
  	 */
  	INIT_LIST_HEAD(&disk_partitions);
09a49930e   Alison Chaiken   GPT: read partiti...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  
  	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
  		ret = part_get_info(dev_desc, p, &info);
  		if (ret)
  			continue;
  
  		/* Add 1 here because counter is zero-based but p1 is
  		   the first partition */
  		new_disk_part = allocate_disk_part(&info, valid_parts+1);
  		if (IS_ERR(new_disk_part))
  			goto out;
  
  		list_add_tail(&new_disk_part->list, &disk_partitions);
  		valid_parts++;
  	}
  	if (valid_parts == 0) {
  		printf("** No valid partitions found **
  ");
  		goto out;
  	}
  	return valid_parts;
   out:
  	if (valid_parts >= 1)
  		del_gpt_info();
  	return -ENODEV;
  }
  
  /* a wrapper to test get_gpt_info */
  static int do_get_gpt_info(struct blk_desc *dev_desc)
  {
  	int ret;
  
  	ret = get_gpt_info(dev_desc);
  	if (ret > 0) {
  		print_gpt_info();
  		del_gpt_info();
  		return 0;
  	}
  	return ret;
  }
  #endif
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
360
  /**
8b0962376   Piotr Wilczek   gpt: Support for ...
361
362
363
364
365
366
367
368
369
370
371
372
   * set_gpt_info(): Fill partition information from string
   *		function allocates memory, remember to free!
   *
   * @param dev_desc - pointer block device descriptor
   * @param str_part - pointer to string with partition information
   * @param str_disk_guid - pointer to pointer to allocated string with disk guid
   * @param partitions - pointer to pointer to allocated partitions array
   * @param parts_count - number of partitions
   *
   * @return - zero on success, otherwise error
   *
   */
4101f6879   Simon Glass   dm: Drop the bloc...
373
  static int set_gpt_info(struct blk_desc *dev_desc,
8b0962376   Piotr Wilczek   gpt: Support for ...
374
375
376
377
378
379
380
381
382
383
384
  			const char *str_part,
  			char **str_disk_guid,
  			disk_partition_t **partitions,
  			u8 *parts_count)
  {
  	char *tok, *str, *s;
  	int i;
  	char *val, *p;
  	int p_count;
  	disk_partition_t *parts;
  	int errno = 0;
3e34cf7bf   Piotr Wilczek   gpt: fix partion ...
385
  	uint64_t size_ll, start_ll;
666362356   Michael Trimarchi   cmd: gpt: add - p...
386
  	lbaint_t offset = 0;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
387
  	int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
8b0962376   Piotr Wilczek   gpt: Support for ...
388

619f0fdf3   Egbert Eich   cmd/gpt: Support ...
389
390
  	debug("%s:  lba num: 0x%x %d
  ", __func__,
8b0962376   Piotr Wilczek   gpt: Support for ...
391
392
393
394
395
396
  	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
  
  	if (str_part == NULL)
  		return -1;
  
  	str = strdup(str_part);
203f9b48a   Alison Chaiken   GPT: provide comm...
397
398
  	if (str == NULL)
  		return -ENOMEM;
8b0962376   Piotr Wilczek   gpt: Support for ...
399
400
401
  
  	/* extract disk guid */
  	s = str;
0c7e8d131   Rob Herring   gpt: support rand...
402
  	val = extract_val(str, "uuid_disk");
8b0962376   Piotr Wilczek   gpt: Support for ...
403
  	if (!val) {
0c7e8d131   Rob Herring   gpt: support rand...
404
405
  #ifdef CONFIG_RANDOM_UUID
  		*str_disk_guid = malloc(UUID_STR_LEN + 1);
bf52fcdef   Tom Rini   cmd/gpt.c, cmd/nv...
406
  		if (*str_disk_guid == NULL)
2fcaa413b   Alison Chaiken   gpt: harden set_g...
407
  			return -ENOMEM;
0c7e8d131   Rob Herring   gpt: support rand...
408
409
  		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
  #else
8b0962376   Piotr Wilczek   gpt: Support for ...
410
411
  		free(str);
  		return -2;
0c7e8d131   Rob Herring   gpt: support rand...
412
413
414
415
416
417
418
419
420
  #endif
  	} else {
  		val = strsep(&val, ";");
  		if (extract_env(val, &p))
  			p = val;
  		*str_disk_guid = strdup(p);
  		free(val);
  		/* Move s to first partition */
  		strsep(&s, ";");
8b0962376   Piotr Wilczek   gpt: Support for ...
421
  	}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
422
423
424
425
426
427
  	if (s == NULL) {
  		printf("Error: is the partitions string NULL-terminated?
  ");
  		return -EINVAL;
  	}
  	if (strnlen(s, max_str_part) == 0)
8b0962376   Piotr Wilczek   gpt: Support for ...
428
  		return -3;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
429
  	i = strnlen(s, max_str_part) - 1;
8b0962376   Piotr Wilczek   gpt: Support for ...
430
431
432
433
434
435
436
437
438
439
440
441
442
  	if (s[i] == ';')
  		s[i] = '\0';
  
  	/* calculate expected number of partitions */
  	p_count = 1;
  	p = s;
  	while (*p) {
  		if (*p++ == ';')
  			p_count++;
  	}
  
  	/* allocate memory for partitions */
  	parts = calloc(sizeof(disk_partition_t), p_count);
2fcaa413b   Alison Chaiken   gpt: harden set_g...
443
444
  	if (parts == NULL)
  		return -ENOMEM;
8b0962376   Piotr Wilczek   gpt: Support for ...
445

1f8b546f9   Robert P. J. Day   Fix some obvious ...
446
  	/* retrieve partitions data from string */
8b0962376   Piotr Wilczek   gpt: Support for ...
447
448
449
450
451
452
453
454
  	for (i = 0; i < p_count; i++) {
  		tok = strsep(&s, ";");
  
  		if (tok == NULL)
  			break;
  
  		/* uuid */
  		val = extract_val(tok, "uuid");
0c7e8d131   Rob Herring   gpt: support rand...
455
456
457
458
459
  		if (!val) {
  			/* 'uuid' is optional if random uuid's are enabled */
  #ifdef CONFIG_RANDOM_UUID
  			gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
  #else
8b0962376   Piotr Wilczek   gpt: Support for ...
460
461
  			errno = -4;
  			goto err;
0c7e8d131   Rob Herring   gpt: support rand...
462
463
464
465
  #endif
  		} else {
  			if (extract_env(val, &p))
  				p = val;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
466
  			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
0c7e8d131   Rob Herring   gpt: support rand...
467
468
469
470
471
  				printf("Wrong uuid format for partition %d
  ", i);
  				errno = -4;
  				goto err;
  			}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
472
  			strncpy((char *)parts[i].uuid, p, max_str_part);
0c7e8d131   Rob Herring   gpt: support rand...
473
  			free(val);
8b0962376   Piotr Wilczek   gpt: Support for ...
474
  		}
7561b258a   Patrick Delaunay   gpt: add optional...
475
476
477
478
479
480
481
  #ifdef CONFIG_PARTITION_TYPE_GUID
  		/* guid */
  		val = extract_val(tok, "type");
  		if (val) {
  			/* 'type' is optional */
  			if (extract_env(val, &p))
  				p = val;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
482
  			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
7561b258a   Patrick Delaunay   gpt: add optional...
483
484
485
486
487
488
  				printf("Wrong type guid format for partition %d
  ",
  				       i);
  				errno = -4;
  				goto err;
  			}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
489
  			strncpy((char *)parts[i].type_guid, p, max_str_part);
7561b258a   Patrick Delaunay   gpt: add optional...
490
491
492
  			free(val);
  		}
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
493
494
495
496
497
498
499
500
  		/* name */
  		val = extract_val(tok, "name");
  		if (!val) { /* name is mandatory */
  			errno = -4;
  			goto err;
  		}
  		if (extract_env(val, &p))
  			p = val;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
501
  		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
8b0962376   Piotr Wilczek   gpt: Support for ...
502
503
504
  			errno = -4;
  			goto err;
  		}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
505
  		strncpy((char *)parts[i].name, p, max_str_part);
8b0962376   Piotr Wilczek   gpt: Support for ...
506
507
508
509
510
511
512
513
514
515
  		free(val);
  
  		/* size */
  		val = extract_val(tok, "size");
  		if (!val) { /* 'size' is mandatory */
  			errno = -4;
  			goto err;
  		}
  		if (extract_env(val, &p))
  			p = val;
666362356   Michael Trimarchi   cmd: gpt: add - p...
516
  		if ((strcmp(p, "-") == 0)) {
c2fdd3456   Kever Yang   cmd: gpt: fix the...
517
518
  			/* Let part efi module to auto extend the size */
  			parts[i].size = 0;
666362356   Michael Trimarchi   cmd: gpt: add - p...
519
520
521
522
  		} else {
  			size_ll = ustrtoull(p, &p, 0);
  			parts[i].size = lldiv(size_ll, dev_desc->blksz);
  		}
8b0962376   Piotr Wilczek   gpt: Support for ...
523
524
525
526
527
528
529
  		free(val);
  
  		/* start address */
  		val = extract_val(tok, "start");
  		if (val) { /* start address is optional */
  			if (extract_env(val, &p))
  				p = val;
3e34cf7bf   Piotr Wilczek   gpt: fix partion ...
530
531
  			start_ll = ustrtoull(p, &p, 0);
  			parts[i].start = lldiv(start_ll, dev_desc->blksz);
8b0962376   Piotr Wilczek   gpt: Support for ...
532
533
  			free(val);
  		}
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
534

666362356   Michael Trimarchi   cmd: gpt: add - p...
535
  		offset += parts[i].size + parts[i].start;
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
536
537
538
  		/* bootable */
  		if (found_key(tok, "bootable"))
  			parts[i].bootable = 1;
8b0962376   Piotr Wilczek   gpt: Support for ...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  	}
  
  	*parts_count = p_count;
  	*partitions = parts;
  	free(str);
  
  	return 0;
  err:
  	free(str);
  	free(*str_disk_guid);
  	free(parts);
  
  	return errno;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
553
  static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part)
8b0962376   Piotr Wilczek   gpt: Support for ...
554
555
556
557
558
  {
  	int ret;
  	char *str_disk_guid;
  	u8 part_count = 0;
  	disk_partition_t *partitions = NULL;
8b0962376   Piotr Wilczek   gpt: Support for ...
559
  	/* fill partitions */
619f0fdf3   Egbert Eich   cmd/gpt: Support ...
560
  	ret = set_gpt_info(blk_dev_desc, str_part,
8b0962376   Piotr Wilczek   gpt: Support for ...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  			&str_disk_guid, &partitions, &part_count);
  	if (ret) {
  		if (ret == -1)
  			printf("No partition list provided
  ");
  		if (ret == -2)
  			printf("Missing disk guid
  ");
  		if ((ret == -3) || (ret == -4))
  			printf("Partition list incomplete
  ");
  		return -1;
  	}
  
  	/* save partitions layout to disk */
a150e6c9d   Rob Herring   gpt: fix error re...
576
  	ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
8b0962376   Piotr Wilczek   gpt: Support for ...
577
578
  	free(str_disk_guid);
  	free(partitions);
a150e6c9d   Rob Herring   gpt: fix error re...
579
  	return ret;
8b0962376   Piotr Wilczek   gpt: Support for ...
580
  }
4101f6879   Simon Glass   dm: Drop the bloc...
581
  static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  {
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
  				     blk_dev_desc->blksz);
  	disk_partition_t *partitions = NULL;
  	gpt_entry *gpt_pte = NULL;
  	char *str_disk_guid;
  	u8 part_count = 0;
  	int ret = 0;
  
  	/* fill partitions */
  	ret = set_gpt_info(blk_dev_desc, str_part,
  			&str_disk_guid, &partitions, &part_count);
  	if (ret) {
  		if (ret == -1) {
  			printf("No partition list provided - only basic check
  ");
  			ret = gpt_verify_headers(blk_dev_desc, gpt_head,
  						 &gpt_pte);
  			goto out;
  		}
  		if (ret == -2)
  			printf("Missing disk guid
  ");
  		if ((ret == -3) || (ret == -4))
  			printf("Partition list incomplete
  ");
  		return -1;
  	}
  
  	/* Check partition layout with provided pattern */
  	ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count,
  				    gpt_head, &gpt_pte);
  	free(str_disk_guid);
  	free(partitions);
   out:
  	free(gpt_pte);
  	return ret;
  }
73d6d18b7   Alison Chaiken   GPT: add accessor...
620
621
622
623
624
625
626
627
628
629
  static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
  {
  	int ret;
  	char disk_guid[UUID_STR_LEN + 1];
  
  	ret = get_disk_guid(dev_desc, disk_guid);
  	if (ret < 0)
  		return CMD_RET_FAILURE;
  
  	if (namestr)
382bee57f   Simon Glass   env: Rename seten...
630
  		env_set(namestr, disk_guid);
73d6d18b7   Alison Chaiken   GPT: add accessor...
631
632
633
634
635
636
  	else
  		printf("%s
  ", disk_guid);
  
  	return ret;
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
637
  #ifdef CONFIG_CMD_GPT_RENAME
18030d04d   Alison Chaiken   GPT: fix memory l...
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  /*
   * There are 3 malloc() calls in set_gpt_info() and there is no info about which
   * failed.
   */
  static void set_gpt_cleanup(char **str_disk_guid,
  			    disk_partition_t **partitions)
  {
  #ifdef CONFIG_RANDOM_UUID
  	if (str_disk_guid)
  		free(str_disk_guid);
  #endif
  	if (partitions)
  		free(partitions);
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
  			       char *name1, char *name2)
  {
  	struct list_head *pos;
  	struct disk_part *curr;
  	disk_partition_t *new_partitions = NULL;
  	char disk_guid[UUID_STR_LEN + 1];
  	char *partitions_list, *str_disk_guid;
  	u8 part_count = 0;
  	int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
  
  	if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
  	    (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
  		return -EINVAL;
  
  	ret = get_disk_guid(dev_desc, disk_guid);
  	if (ret < 0)
  		return ret;
18030d04d   Alison Chaiken   GPT: fix memory l...
670
671
672
673
  	/*
  	 * Allocates disk_partitions, requiring matching call to del_gpt_info()
  	 * if successful.
  	 */
203f9b48a   Alison Chaiken   GPT: provide comm...
674
675
676
677
678
679
  	numparts = get_gpt_info(dev_desc);
  	if (numparts <=  0)
  		return numparts ? numparts : -ENODEV;
  
  	partlistlen = calc_parts_list_len(numparts);
  	partitions_list = malloc(partlistlen);
18030d04d   Alison Chaiken   GPT: fix memory l...
680
681
  	if (!partitions_list) {
  		del_gpt_info();
203f9b48a   Alison Chaiken   GPT: provide comm...
682
  		return -ENOMEM;
18030d04d   Alison Chaiken   GPT: fix memory l...
683
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
684
685
686
  	memset(partitions_list, '\0', partlistlen);
  
  	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
18030d04d   Alison Chaiken   GPT: fix memory l...
687
688
  	if (ret < 0) {
  		free(partitions_list);
203f9b48a   Alison Chaiken   GPT: provide comm...
689
  		return ret;
18030d04d   Alison Chaiken   GPT: fix memory l...
690
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
691
692
693
694
695
696
697
  	/*
  	 * Uncomment the following line to print a string that 'gpt write'
  	 * or 'gpt verify' will accept as input.
  	 */
  	debug("OLD partitions_list is %s with %u chars
  ", partitions_list,
  	      (unsigned)strlen(partitions_list));
18030d04d   Alison Chaiken   GPT: fix memory l...
698
  	/* set_gpt_info allocates new_partitions and str_disk_guid */
203f9b48a   Alison Chaiken   GPT: provide comm...
699
700
  	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
  			   &new_partitions, &part_count);
18030d04d   Alison Chaiken   GPT: fix memory l...
701
702
703
704
705
706
707
708
  	if (ret < 0) {
  		del_gpt_info();
  		free(partitions_list);
  		if (ret == -ENOMEM)
  			set_gpt_cleanup(&str_disk_guid, &new_partitions);
  		else
  			goto out;
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
709
710
711
712
713
  
  	if (!strcmp(subcomm, "swap")) {
  		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
  			printf("Names longer than %d characters are truncated.
  ", PART_NAME_LEN);
18030d04d   Alison Chaiken   GPT: fix memory l...
714
715
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
  		}
  		list_for_each(pos, &disk_partitions) {
  			curr = list_entry(pos, struct disk_part, list);
  			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
  				strcpy((char *)curr->gpt_part_info.name, name2);
  				ctr1++;
  			} else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
  				strcpy((char *)curr->gpt_part_info.name, name1);
  				ctr2++;
  			}
  		}
  		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
  			printf("Cannot swap partition names except in pairs.
  ");
18030d04d   Alison Chaiken   GPT: fix memory l...
730
731
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
732
733
734
735
736
  		}
  	} else { /* rename */
  		if (strlen(name2) > PART_NAME_LEN) {
  			printf("Names longer than %d characters are truncated.
  ", PART_NAME_LEN);
18030d04d   Alison Chaiken   GPT: fix memory l...
737
738
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
739
740
741
742
743
  		}
  		partnum = (int)simple_strtol(name1, NULL, 10);
  		if ((partnum < 0) || (partnum > numparts)) {
  			printf("Illegal partition number %s
  ", name1);
18030d04d   Alison Chaiken   GPT: fix memory l...
744
745
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
746
747
748
  		}
  		ret = part_get_info(dev_desc, partnum, new_partitions);
  		if (ret < 0)
18030d04d   Alison Chaiken   GPT: fix memory l...
749
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  
  		/* U-Boot partition numbering starts at 1 */
  		list_for_each(pos, &disk_partitions) {
  			curr = list_entry(pos, struct disk_part, list);
  			if (i == partnum) {
  				strcpy((char *)curr->gpt_part_info.name, name2);
  				break;
  			}
  			i++;
  		}
  	}
  
  	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
  	if (ret < 0)
18030d04d   Alison Chaiken   GPT: fix memory l...
764
  		goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
765
766
767
768
769
770
  	debug("NEW partitions_list is %s with %u chars
  ", partitions_list,
  	      (unsigned)strlen(partitions_list));
  
  	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
  			   &new_partitions, &part_count);
18030d04d   Alison Chaiken   GPT: fix memory l...
771
772
773
774
775
776
777
778
779
780
781
782
  	/*
  	 * Even though valid pointers are here passed into set_gpt_info(),
  	 * it mallocs again, and there's no way to tell which failed.
  	 */
  	if (ret < 0) {
  		del_gpt_info();
  		free(partitions_list);
  		if (ret == -ENOMEM)
  			set_gpt_cleanup(&str_disk_guid, &new_partitions);
  		else
  			goto out;
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
783
784
785
786
787
788
789
  
  	debug("Writing new partition table
  ");
  	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
  	if (ret < 0) {
  		printf("Writing new partition table failed
  ");
18030d04d   Alison Chaiken   GPT: fix memory l...
790
  		goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
791
792
793
794
  	}
  
  	debug("Reading back new partition table
  ");
18030d04d   Alison Chaiken   GPT: fix memory l...
795
796
797
798
799
  	/*
  	 * Empty the existing disk_partitions list, as otherwise the memory in
  	 * the original list is unreachable.
  	 */
  	del_gpt_info();
203f9b48a   Alison Chaiken   GPT: provide comm...
800
  	numparts = get_gpt_info(dev_desc);
18030d04d   Alison Chaiken   GPT: fix memory l...
801
802
803
804
  	if (numparts <=  0) {
  		ret = numparts ? numparts : -ENODEV;
  		goto out;
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
805
806
807
  	printf("new partition table with %d partitions is:
  ", numparts);
  	print_gpt_info();
203f9b48a   Alison Chaiken   GPT: provide comm...
808
  	del_gpt_info();
18030d04d   Alison Chaiken   GPT: fix memory l...
809
   out:
203f9b48a   Alison Chaiken   GPT: provide comm...
810
  	free(new_partitions);
18030d04d   Alison Chaiken   GPT: fix memory l...
811
812
  	free(str_disk_guid);
  	free(partitions_list);
203f9b48a   Alison Chaiken   GPT: provide comm...
813
814
815
  	return ret;
  }
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  /**
   * do_gpt(): Perform GPT operations
   *
   * @param cmdtp - command name
   * @param flag
   * @param argc
   * @param argv
   *
   * @return zero on success; otherwise error
   */
  static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  {
  	int ret = CMD_RET_SUCCESS;
  	int dev = 0;
619f0fdf3   Egbert Eich   cmd/gpt: Support ...
830
  	char *ep;
4101f6879   Simon Glass   dm: Drop the bloc...
831
  	struct blk_desc *blk_dev_desc = NULL;
8b0962376   Piotr Wilczek   gpt: Support for ...
832

203f9b48a   Alison Chaiken   GPT: provide comm...
833
  #ifndef CONFIG_CMD_GPT_RENAME
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
834
  	if (argc < 4 || argc > 5)
203f9b48a   Alison Chaiken   GPT: provide comm...
835
836
837
  #else
  	if (argc < 4 || argc > 6)
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
838
  		return CMD_RET_USAGE;
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
839
840
841
842
843
844
  	dev = (int)simple_strtoul(argv[3], &ep, 10);
  	if (!ep || ep[0] != '\0') {
  		printf("'%s' is not a number
  ", argv[3]);
  		return CMD_RET_USAGE;
  	}
db1d9e78e   Simon Glass   dm: blk: Rename g...
845
  	blk_dev_desc = blk_get_dev(argv[2], dev);
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
846
847
848
849
850
851
  	if (!blk_dev_desc) {
  		printf("%s: %s dev %d NOT available
  ",
  		       __func__, argv[2], dev);
  		return CMD_RET_FAILURE;
  	}
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
852

bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
853
854
  	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
  		printf("Writing GPT: ");
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
855
  		ret = gpt_default(blk_dev_desc, argv[4]);
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
856
857
858
  	} else if ((strcmp(argv[1], "verify") == 0)) {
  		ret = gpt_verify(blk_dev_desc, argv[4]);
  		printf("Verify GPT: ");
73d6d18b7   Alison Chaiken   GPT: add accessor...
859
860
  	} else if (strcmp(argv[1], "guid") == 0) {
  		ret = do_disk_guid(blk_dev_desc, argv[4]);
09a49930e   Alison Chaiken   GPT: read partiti...
861
862
863
  #ifdef CONFIG_CMD_GPT_RENAME
  	} else if (strcmp(argv[1], "read") == 0) {
  		ret = do_get_gpt_info(blk_dev_desc);
203f9b48a   Alison Chaiken   GPT: provide comm...
864
865
866
  	} else if ((strcmp(argv[1], "swap") == 0) ||
  		   (strcmp(argv[1], "rename") == 0)) {
  		ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
09a49930e   Alison Chaiken   GPT: read partiti...
867
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
868
869
870
  	} else {
  		return CMD_RET_USAGE;
  	}
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
871
872
873
874
875
876
877
878
879
880
  
  	if (ret) {
  		printf("error!
  ");
  		return CMD_RET_FAILURE;
  	}
  
  	printf("success!
  ");
  	return CMD_RET_SUCCESS;
8b0962376   Piotr Wilczek   gpt: Support for ...
881
882
883
884
  }
  
  U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
  	"GUID Partition Table",
1f8b546f9   Robert P. J. Day   Fix some obvious ...
885
886
  	"<command> <interface> <dev> <partitions_list>
  "
74f889b03   Lukasz Majewski   gpt: doc: Update ...
887
888
889
890
  	" - GUID partition table restoration and validity check
  "
  	" Restore or verify GPT information on a device connected
  "
8b0962376   Piotr Wilczek   gpt: Support for ...
891
892
  	" to interface
  "
74f889b03   Lukasz Majewski   gpt: doc: Update ...
893
894
895
896
897
898
  	" Example usage:
  "
  	" gpt write mmc 0 $partitions
  "
  	" gpt verify mmc 0 $partitions
  "
09a49930e   Alison Chaiken   GPT: read partiti...
899
900
901
902
  	" read <interface> <dev>
  "
  	"    - read GPT into a data structure for manipulation
  "
73d6d18b7   Alison Chaiken   GPT: add accessor...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  	" guid <interface> <dev>
  "
  	"    - print disk GUID
  "
  	" guid <interface> <dev> <varname>
  "
  	"    - set environment variable to disk GUID
  "
  	" Example usage:
  "
  	" gpt guid mmc 0
  "
  	" gpt guid mmc 0 varname
  "
203f9b48a   Alison Chaiken   GPT: provide comm...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
  #ifdef CONFIG_CMD_GPT_RENAME
  	"gpt partition renaming commands:
  "
  	"gpt swap <interface> <dev> <name1> <name2>
  "
  	"    - change all partitions named name1 to name2
  "
  	"      and vice-versa
  "
  	"gpt rename <interface> <dev> <part> <name>
  "
  	"    - rename the specified partition
  "
  	" Example usage:
  "
  	" gpt swap mmc 0 foo bar
  "
  	" gpt rename mmc 0 3 foo
  "
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
937
  );