part.c 17.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
wdenk's avatar
wdenk committed
2
3
4
5
6
7
/*
 * (C) Copyright 2001
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 */

#include <common.h>
8
#include <blk.h>
wdenk's avatar
wdenk committed
9
#include <command.h>
Simon Glass's avatar
Simon Glass committed
10
#include <env.h>
11
#include <errno.h>
wdenk's avatar
wdenk committed
12
#include <ide.h>
13
#include <log.h>
14
#include <malloc.h>
15
#include <part.h>
Hans de Goede's avatar
Hans de Goede committed
16
#include <ubifs_uboot.h>
wdenk's avatar
wdenk committed
17
18
19
20
21
22
23
24
25

#undef	PART_DEBUG

#ifdef	PART_DEBUG
#define	PRINTF(fmt,args...)	printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif

26
27
28
/* Check all partition types */
#define PART_TYPE_ALL		-1

29
static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
30
31
32
33
34
35
{
	struct part_driver *drv =
		ll_entry_start(struct part_driver, part_driver);
	const int n_ents = ll_entry_count(struct part_driver, part_driver);
	struct part_driver *entry;

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
	if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
		for (entry = drv; entry != drv + n_ents; entry++) {
			int ret;

			ret = entry->test(dev_desc);
			if (!ret) {
				dev_desc->part_type = entry->part_type;
				return entry;
			}
		}
	} else {
		for (entry = drv; entry != drv + n_ents; entry++) {
			if (dev_desc->part_type == entry->part_type)
				return entry;
		}
51
52
53
54
55
56
	}

	/* Not found */
	return NULL;
}

57
#ifdef CONFIG_HAVE_BLOCK_DEVICE
58
static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
59
{
60
61
	struct blk_desc *dev_desc;
	int ret;
62

63
64
65
66
	dev_desc = blk_get_devnum_by_typename(ifname, dev);
	if (!dev_desc) {
		debug("%s: No device for iface '%s', dev %d\n", __func__,
		      ifname, dev);
67
		return NULL;
68
	}
69
70
71
72
73
74
75
76
	ret = blk_dselect_hwpart(dev_desc, hwpart);
	if (ret) {
		debug("%s: Failed to select h/w partition: err-%d\n", __func__,
		      ret);
		return NULL;
	}

	return dev_desc;
77
}
78

79
struct blk_desc *blk_get_dev(const char *ifname, int dev)
80
{
81
	return get_dev_hwpart(ifname, dev, 0);
82
}
83
#else
84
struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
85
86
87
88
{
	return NULL;
}

89
struct blk_desc *blk_get_dev(const char *ifname, int dev)
90
91
92
93
94
{
	return NULL;
}
#endif

95
#ifdef CONFIG_HAVE_BLOCK_DEVICE
wdenk's avatar
wdenk committed
96
97
98
99
100

/* ------------------------------------------------------------------------- */
/*
 * reports device info to the user
 */
101

102
#ifdef CONFIG_LBA48
103
typedef uint64_t lba512_t;
104
#else
105
typedef lbaint_t lba512_t;
106
#endif
wdenk's avatar
wdenk committed
107

108
/*
109
110
 * Overflowless variant of (block_count * mul_by / 2**right_shift)
 * when 2**right_shift > mul_by
111
 */
112
113
static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by,
			      int right_shift)
114
115
116
117
{
	lba512_t bc_quot, bc_rem;

	/* x * m / d == x / d * m + (x % d) * m / d */
118
119
120
	bc_quot = block_count >> right_shift;
	bc_rem  = block_count - (bc_quot << right_shift);
	return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift);
121
122
}

123
void dev_print (struct blk_desc *dev_desc)
124
125
126
{
	lba512_t lba512; /* number of blocks if 512bytes block size */

127
128
129
130
131
	if (dev_desc->type == DEV_TYPE_UNKNOWN) {
		puts ("not available\n");
		return;
	}

132
	switch (dev_desc->if_type) {
133
134
135
	case IF_TYPE_SCSI:
		printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
			dev_desc->target,dev_desc->lun,
wdenk's avatar
wdenk committed
136
			dev_desc->vendor,
137
138
139
			dev_desc->product,
			dev_desc->revision);
		break;
140
	case IF_TYPE_ATAPI:
141
142
	case IF_TYPE_IDE:
	case IF_TYPE_SATA:
143
144
145
146
		printf ("Model: %s Firm: %s Ser#: %s\n",
			dev_desc->vendor,
			dev_desc->revision,
			dev_desc->product);
147
		break;
148
149
	case IF_TYPE_SD:
	case IF_TYPE_MMC:
150
	case IF_TYPE_USB:
151
	case IF_TYPE_NVME:
152
	case IF_TYPE_PVBLOCK:
153
	case IF_TYPE_HOST:
154
155
156
157
158
		printf ("Vendor: %s Rev: %s Prod: %s\n",
			dev_desc->vendor,
			dev_desc->revision,
			dev_desc->product);
		break;
159
160
161
	case IF_TYPE_VIRTIO:
		printf("%s VirtIO Block Device\n", dev_desc->vendor);
		break;
162
163
164
	case IF_TYPE_DOC:
		puts("device type DOC\n");
		return;
165
	case IF_TYPE_UNKNOWN:
166
167
		puts("device type unknown\n");
		return;
168
	default:
169
		printf("Unhandled device type: %i\n", dev_desc->if_type);
170
		return;
wdenk's avatar
wdenk committed
171
172
173
174
175
	}
	puts ("            Type: ");
	if (dev_desc->removable)
		puts ("Removable ");
	switch (dev_desc->type & 0x1F) {
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
	case DEV_TYPE_HARDDISK:
		puts ("Hard Disk");
		break;
	case DEV_TYPE_CDROM:
		puts ("CD ROM");
		break;
	case DEV_TYPE_OPDISK:
		puts ("Optical Device");
		break;
	case DEV_TYPE_TAPE:
		puts ("Tape");
		break;
	default:
		printf ("# %02X #", dev_desc->type & 0x1F);
		break;
wdenk's avatar
wdenk committed
191
192
	}
	puts ("\n");
193
	if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
wdenk's avatar
wdenk committed
194
		ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
195
		lbaint_t lba;
wdenk's avatar
wdenk committed
196
197

		lba = dev_desc->lba;
wdenk's avatar
wdenk committed
198

199
		lba512 = (lba * (dev_desc->blksz/512));
wdenk's avatar
wdenk committed
200
		/* round to 1 digit */
Pavel Machek's avatar
Pavel Machek committed
201
		/* 2048 = (1024 * 1024) / 512 MB */
202
		mb = lba512_muldiv(lba512, 10, 11);
203

wdenk's avatar
wdenk committed
204
205
206
207
208
209
		mb_quot	= mb / 10;
		mb_rem	= mb - (10 * mb_quot);

		gb = mb / 1024;
		gb_quot	= gb / 10;
		gb_rem	= gb - (10 * gb_quot);
210
#ifdef CONFIG_LBA48
wdenk's avatar
wdenk committed
211
		if (dev_desc->lba48)
212
213
			printf ("            Supports 48-bit addressing\n");
#endif
214
#if defined(CONFIG_SYS_64BIT_LBA)
215
		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
216
217
218
219
220
			mb_quot, mb_rem,
			gb_quot, gb_rem,
			lba,
			dev_desc->blksz);
#else
221
		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
wdenk's avatar
wdenk committed
222
223
			mb_quot, mb_rem,
			gb_quot, gb_rem,
224
			(ulong)lba,
wdenk's avatar
wdenk committed
225
			dev_desc->blksz);
226
#endif
wdenk's avatar
wdenk committed
227
228
229
230
	} else {
		puts ("            Capacity: not available\n");
	}
}
231
#endif
wdenk's avatar
wdenk committed
232

233
#ifdef CONFIG_HAVE_BLOCK_DEVICE
wdenk's avatar
wdenk committed
234

235
void part_init(struct blk_desc *dev_desc)
wdenk's avatar
wdenk committed
236
{
237
238
239
240
	struct part_driver *drv =
		ll_entry_start(struct part_driver, part_driver);
	const int n_ents = ll_entry_count(struct part_driver, part_driver);
	struct part_driver *entry;
wdenk's avatar
wdenk committed
241

242
243
	blkcache_invalidate(dev_desc->if_type, dev_desc->devnum);

244
	dev_desc->part_type = PART_TYPE_UNKNOWN;
245
246
247
248
249
250
251
252
253
254
	for (entry = drv; entry != drv + n_ents; entry++) {
		int ret;

		ret = entry->test(dev_desc);
		debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret);
		if (!ret) {
			dev_desc->part_type = entry->part_type;
			break;
		}
	}
wdenk's avatar
wdenk committed
255
256
}

257
258
static void print_part_header(const char *type, struct blk_desc *dev_desc)
{
259
#if CONFIG_IS_ENABLED(MAC_PARTITION) || \
260
	CONFIG_IS_ENABLED(DOS_PARTITION) || \
261
	CONFIG_IS_ENABLED(ISO_PARTITION) || \
262
	CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
263
	CONFIG_IS_ENABLED(EFI_PARTITION)
wdenk's avatar
wdenk committed
264
265
	puts ("\nPartition Map for ");
	switch (dev_desc->if_type) {
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
	case IF_TYPE_IDE:
		puts ("IDE");
		break;
	case IF_TYPE_SATA:
		puts ("SATA");
		break;
	case IF_TYPE_SCSI:
		puts ("SCSI");
		break;
	case IF_TYPE_ATAPI:
		puts ("ATAPI");
		break;
	case IF_TYPE_USB:
		puts ("USB");
		break;
	case IF_TYPE_DOC:
		puts ("DOC");
		break;
Lei Wen's avatar
Lei Wen committed
284
285
286
	case IF_TYPE_MMC:
		puts ("MMC");
		break;
287
	case IF_TYPE_HOST:
288
289
290
291
		puts ("HOST");
		break;
	case IF_TYPE_NVME:
		puts ("NVMe");
292
		break;
293
294
295
	case IF_TYPE_PVBLOCK:
		puts("PV BLOCK");
		break;
296
297
298
	case IF_TYPE_VIRTIO:
		puts("VirtIO");
		break;
299
300
301
	default:
		puts ("UNKNOWN");
		break;
wdenk's avatar
wdenk committed
302
303
	}
	printf (" device %d  --   Partition Type: %s\n\n",
304
			dev_desc->devnum, type);
305
#endif /* any CONFIG_..._PARTITION */
306
}
307

308
void part_print(struct blk_desc *dev_desc)
wdenk's avatar
wdenk committed
309
{
310
	struct part_driver *drv;
wdenk's avatar
wdenk committed
311

312
	drv = part_driver_lookup_type(dev_desc);
313
314
315
	if (!drv) {
		printf("## Unknown partition table type %x\n",
		       dev_desc->part_type);
wdenk's avatar
wdenk committed
316
317
		return;
	}
318
319
320
321
322

	PRINTF("## Testing for valid %s partition ##\n", drv->name);
	print_part_header(drv->name, dev_desc);
	if (drv->print)
		drv->print(dev_desc);
wdenk's avatar
wdenk committed
323
324
}

325
#endif /* CONFIG_HAVE_BLOCK_DEVICE */
326

327
int part_get_info(struct blk_desc *dev_desc, int part,
328
		       struct disk_partition *info)
329
{
330
#ifdef CONFIG_HAVE_BLOCK_DEVICE
331
	struct part_driver *drv;
332

333
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
334
335
336
	/* The common case is no UUID support */
	info->uuid[0] = 0;
#endif
337
338
339
#ifdef CONFIG_PARTITION_TYPE_GUID
	info->type_guid[0] = 0;
#endif
340

341
	drv = part_driver_lookup_type(dev_desc);
342
343
344
345
346
347
	if (!drv) {
		debug("## Unknown partition table type %x\n",
		      dev_desc->part_type);
		return -EPROTONOSUPPORT;
	}
	if (!drv->get_info) {
348
349
		PRINTF("## Driver %s does not have the get_info() method\n",
		       drv->name);
350
351
352
353
354
		return -ENOSYS;
	}
	if (drv->get_info(dev_desc, part, info) == 0) {
		PRINTF("## Valid %s partition found ##\n", drv->name);
		return 0;
355
	}
356
#endif /* CONFIG_HAVE_BLOCK_DEVICE */
357
358
359

	return -1;
}
360

361
362
int part_get_info_whole_disk(struct blk_desc *dev_desc,
			     struct disk_partition *info)
Rob Clark's avatar
Rob Clark committed
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
{
	info->start = 0;
	info->size = dev_desc->lba;
	info->blksz = dev_desc->blksz;
	info->bootable = 0;
	strcpy((char *)info->type, BOOT_PART_TYPE);
	strcpy((char *)info->name, "Whole Disk");
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
	info->uuid[0] = 0;
#endif
#ifdef CONFIG_PARTITION_TYPE_GUID
	info->type_guid[0] = 0;
#endif

	return 0;
}

380
381
int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
			  struct blk_desc **dev_desc)
Stephen Warren's avatar
Stephen Warren committed
382
383
{
	char *ep;
384
385
386
387
388
389
390
391
392
393
394
395
	char *dup_str = NULL;
	const char *dev_str, *hwpart_str;
	int dev, hwpart;

	hwpart_str = strchr(dev_hwpart_str, '.');
	if (hwpart_str) {
		dup_str = strdup(dev_hwpart_str);
		dup_str[hwpart_str - dev_hwpart_str] = 0;
		dev_str = dup_str;
		hwpart_str++;
	} else {
		dev_str = dev_hwpart_str;
396
		hwpart = 0;
397
	}
Stephen Warren's avatar
Stephen Warren committed
398
399
400
401
402

	dev = simple_strtoul(dev_str, &ep, 16);
	if (*ep) {
		printf("** Bad device specification %s %s **\n",
		       ifname, dev_str);
403
		dev = -EINVAL;
404
405
406
407
408
409
410
411
		goto cleanup;
	}

	if (hwpart_str) {
		hwpart = simple_strtoul(hwpart_str, &ep, 16);
		if (*ep) {
			printf("** Bad HW partition specification %s %s **\n",
			    ifname, hwpart_str);
412
			dev = -EINVAL;
413
414
			goto cleanup;
		}
Stephen Warren's avatar
Stephen Warren committed
415
416
	}

417
	*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
Stephen Warren's avatar
Stephen Warren committed
418
	if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
419
		debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
420
		dev = -ENOENT;
421
		goto cleanup;
Stephen Warren's avatar
Stephen Warren committed
422
423
	}

424
#ifdef CONFIG_HAVE_BLOCK_DEVICE
425
426
	/*
	 * Updates the partition table for the specified hw partition.
427
428
	 * Always should be done, otherwise hw partition 0 will return stale
	 * data after displaying a non-zero hw partition.
429
	 */
430
	part_init(*dev_desc);
431
432
#endif

433
434
cleanup:
	free(dup_str);
Stephen Warren's avatar
Stephen Warren committed
435
436
437
	return dev;
}

438
439
#define PART_UNSPECIFIED -2
#define PART_AUTO -1
440
int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
441
			     struct blk_desc **dev_desc,
442
			     struct disk_partition *info, int allow_whole_dev)
443
{
444
445
446
447
	int ret = -1;
	const char *part_str;
	char *dup_str = NULL;
	const char *dev_str;
448
	int dev;
449
450
451
	char *ep;
	int p;
	int part;
452
	struct disk_partition tmpinfo;
453

454
#ifdef CONFIG_SANDBOX
455
	/*
Pavel Machek's avatar
Pavel Machek committed
456
	 * Special-case a pseudo block device "hostfs", to allow access to the
457
458
459
460
461
462
463
464
465
466
	 * host's own filesystem.
	 */
	if (0 == strcmp(ifname, "hostfs")) {
		*dev_desc = NULL;
		info->start = 0;
		info->size = 0;
		info->blksz = 0;
		info->bootable = 0;
		strcpy((char *)info->type, BOOT_PART_TYPE);
		strcpy((char *)info->name, "Sandbox host");
467
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
468
469
		info->uuid[0] = 0;
#endif
470
471
472
#ifdef CONFIG_PARTITION_TYPE_GUID
		info->type_guid[0] = 0;
#endif
473
474
475

		return 0;
	}
476
#endif
477

Hans de Goede's avatar
Hans de Goede committed
478
479
#ifdef CONFIG_CMD_UBIFS
	/*
Heinrich Schuchardt's avatar
Heinrich Schuchardt committed
480
	 * Special-case ubi, ubi goes through a mtd, rather than through
Hans de Goede's avatar
Hans de Goede committed
481
482
483
484
485
486
487
488
489
490
491
492
	 * a regular block device.
	 */
	if (0 == strcmp(ifname, "ubi")) {
		if (!ubifs_is_mounted()) {
			printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
			return -1;
		}

		*dev_desc = NULL;
		memset(info, 0, sizeof(*info));
		strcpy((char *)info->type, BOOT_PART_TYPE);
		strcpy((char *)info->name, "UBI");
493
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
Hans de Goede's avatar
Hans de Goede committed
494
495
496
497
498
499
		info->uuid[0] = 0;
#endif
		return 0;
	}
#endif

500
	/* If no dev_part_str, use bootdevice environment variable */
501
502
	if (!dev_part_str || !strlen(dev_part_str) ||
	    !strcmp(dev_part_str, "-"))
503
		dev_part_str = env_get("bootdevice");
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519

	/* If still no dev_part_str, it's an error */
	if (!dev_part_str) {
		printf("** No device specified **\n");
		goto cleanup;
	}

	/* Separate device and partition ID specification */
	part_str = strchr(dev_part_str, ':');
	if (part_str) {
		dup_str = strdup(dev_part_str);
		dup_str[part_str - dev_part_str] = 0;
		dev_str = dup_str;
		part_str++;
	} else {
		dev_str = dev_part_str;
520
521
	}

522
	/* Look up the device */
523
	dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
	if (dev < 0)
		goto cleanup;

	/* Convert partition ID string to number */
	if (!part_str || !*part_str) {
		part = PART_UNSPECIFIED;
	} else if (!strcmp(part_str, "auto")) {
		part = PART_AUTO;
	} else {
		/* Something specified -> use exactly that */
		part = (int)simple_strtoul(part_str, &ep, 16);
		/*
		 * Less than whole string converted,
		 * or request for whole device, but caller requires partition.
		 */
		if (*ep || (part == 0 && !allow_whole_dev)) {
			printf("** Bad partition specification %s %s **\n",
			    ifname, dev_part_str);
			goto cleanup;
		}
	}

	/*
	 * No partition table on device,
	 * or user requested partition 0 (entire device).
	 */
	if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
	    (part == 0)) {
		if (!(*dev_desc)->lba) {
			printf("** Bad device size - %s %s **\n", ifname,
			       dev_str);
			goto cleanup;
		}
557

558
559
560
561
562
563
564
565
566
		/*
		 * If user specified a partition ID other than 0,
		 * or the calling command only accepts partitions,
		 * it's an error.
		 */
		if ((part > 0) || (!allow_whole_dev)) {
			printf("** No partition table - %s %s **\n", ifname,
			       dev_str);
			goto cleanup;
567
		}
568

569
570
		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);

Rob Clark's avatar
Rob Clark committed
571
		part_get_info_whole_disk(*dev_desc, info);
572

573
574
		ret = 0;
		goto cleanup;
575
576
	}

577
578
579
580
581
582
583
584
585
586
587
588
	/*
	 * Now there's known to be a partition table,
	 * not specifying a partition means to pick partition 1.
	 */
	if (part == PART_UNSPECIFIED)
		part = 1;

	/*
	 * If user didn't specify a partition number, or did specify something
	 * other than "auto", use that partition number directly.
	 */
	if (part != PART_AUTO) {
589
		ret = part_get_info(*dev_desc, part, info);
590
591
592
593
594
595
596
597
598
599
600
		if (ret) {
			printf("** Invalid partition %d **\n", part);
			goto cleanup;
		}
	} else {
		/*
		 * Find the first bootable partition.
		 * If none are bootable, fall back to the first valid partition.
		 */
		part = 0;
		for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
601
			ret = part_get_info(*dev_desc, p, info);
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
			if (ret)
				continue;

			/*
			 * First valid partition, or new better partition?
			 * If so, save partition ID.
			 */
			if (!part || info->bootable)
				part = p;

			/* Best possible partition? Stop searching. */
			if (info->bootable)
				break;

			/*
			 * We now need to search further for best possible.
			 * If we what we just queried was the best so far,
			 * save the info since we over-write it next loop.
			 */
			if (part == p)
				tmpinfo = *info;
		}
		/* If we found any acceptable partition */
		if (part) {
			/*
			 * If we searched all possible partition IDs,
			 * return the first valid partition we found.
			 */
			if (p == MAX_SEARCH_PARTITIONS + 1)
				*info = tmpinfo;
		} else {
			printf("** No valid partitions found **\n");
634
			ret = -1;
635
636
			goto cleanup;
		}
637
638
639
640
641
	}
	if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
		printf("** Invalid partition type \"%.32s\""
			" (expect \"" BOOT_PART_TYPE "\")\n",
			info->type);
642
643
		ret  = -1;
		goto cleanup;
644
645
	}

646
647
	(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);

648
649
	ret = part;
	goto cleanup;
650

651
652
653
cleanup:
	free(dup_str);
	return ret;
654
}
655

656
int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
657
			       struct disk_partition *info, int part_type)
658
659
{
	struct part_driver *part_drv;
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
	int ret;
	int i;

	part_drv = part_driver_lookup_type(dev_desc);
	if (!part_drv)
		return -1;
	for (i = 1; i < part_drv->max_entries; i++) {
		ret = part_drv->get_info(dev_desc, i, info);
		if (ret != 0) {
			/* no more entries in table */
			break;
		}
		if (strcmp(name, (const char *)info->name) == 0) {
			/* matched */
			return i;
675
676
		}
	}
677

678
679
	return -1;
}
680

681
int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
682
			  struct disk_partition *info)
683
684
685
686
{
	return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
}

687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
/**
 * Get partition info from device number and partition name.
 *
 * Parse a device number and partition name string in the form of
 * "device_num#partition_name", for example "0#misc". If the partition
 * is found, sets dev_desc and part_info accordingly with the information
 * of the partition with the given partition_name.
 *
 * @param[in] dev_iface Device interface
 * @param[in] dev_part_str Input string argument, like "0#misc"
 * @param[out] dev_desc Place to store the device description pointer
 * @param[out] part_info Place to store the partition information
 * @return 0 on success, or a negative on error
 */
static int part_get_info_by_dev_and_name(const char *dev_iface,
					 const char *dev_part_str,
					 struct blk_desc **dev_desc,
704
					 struct disk_partition *part_info)
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
{
	char *ep;
	const char *part_str;
	int dev_num;

	part_str = strchr(dev_part_str, '#');
	if (!part_str || part_str == dev_part_str)
		return -EINVAL;

	dev_num = simple_strtoul(dev_part_str, &ep, 16);
	if (ep != part_str) {
		/* Not all the first part before the # was parsed. */
		return -EINVAL;
	}
	part_str++;

	*dev_desc = blk_get_dev(dev_iface, dev_num);
	if (!*dev_desc) {
		printf("Could not find %s %d\n", dev_iface, dev_num);
		return -EINVAL;
	}
	if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
		printf("Could not find \"%s\" partition\n", part_str);
		return -EINVAL;
	}
	return 0;
}

int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
					 const char *dev_part_str,
					 struct blk_desc **dev_desc,
736
					 struct disk_partition *part_info)
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
{
	/* Split the part_name if passed as "$dev_num#part_name". */
	if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str,
					   dev_desc, part_info))
		return 0;
	/*
	 * Couldn't lookup by name, try looking up the partition description
	 * directly.
	 */
	if (blk_get_device_part_str(dev_iface, dev_part_str,
				    dev_desc, part_info, 1) < 0) {
		printf("Couldn't find partition %s %s\n",
		       dev_iface, dev_part_str);
		return -EINVAL;
	}
	return 0;
}

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
void part_set_generic_name(const struct blk_desc *dev_desc,
	int part_num, char *name)
{
	char *devtype;

	switch (dev_desc->if_type) {
	case IF_TYPE_IDE:
	case IF_TYPE_SATA:
	case IF_TYPE_ATAPI:
		devtype = "hd";
		break;
	case IF_TYPE_SCSI:
		devtype = "sd";
		break;
	case IF_TYPE_USB:
		devtype = "usbd";
		break;
	case IF_TYPE_DOC:
		devtype = "docd";
		break;
	case IF_TYPE_MMC:
	case IF_TYPE_SD:
		devtype = "mmcsd";
		break;
	default:
		devtype = "xx";
		break;
	}

	sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
}