part.c 15.6 KB
Newer Older
W
wdenk 已提交
1 2 3 4
/*
 * (C) Copyright 2001
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
5
 * SPDX-License-Identifier:	GPL-2.0+
W
wdenk 已提交
6 7 8 9 10
 */

#include <common.h>
#include <command.h>
#include <ide.h>
11
#include <malloc.h>
12
#include <part.h>
H
Hans de Goede 已提交
13
#include <ubifs_uboot.h>
W
wdenk 已提交
14 15 16 17 18 19 20 21 22

#undef	PART_DEBUG

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

23 24 25
struct block_drvr {
	char *name;
	block_dev_desc_t* (*get_dev)(int dev);
26
	int (*select_hwpart)(int dev_num, int hwpart);
27 28 29
};

static const struct block_drvr block_drvr[] = {
30
#if defined(CONFIG_CMD_IDE)
31 32
	{ .name = "ide", .get_dev = ide_get_dev, },
#endif
33 34 35
#if defined(CONFIG_CMD_SATA)
	{.name = "sata", .get_dev = sata_get_dev, },
#endif
36
#if defined(CONFIG_CMD_SCSI)
37 38
	{ .name = "scsi", .get_dev = scsi_get_dev, },
#endif
39
#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
40 41 42
	{ .name = "usb", .get_dev = usb_stor_get_dev, },
#endif
#if defined(CONFIG_MMC)
43 44 45 46 47
	{
		.name = "mmc",
		.get_dev = mmc_get_dev,
		.select_hwpart = mmc_select_hwpart,
	},
48 49 50
#endif
#if defined(CONFIG_SYSTEMACE)
	{ .name = "ace", .get_dev = systemace_get_dev, },
51 52 53
#endif
#if defined(CONFIG_SANDBOX)
	{ .name = "host", .get_dev = host_get_dev, },
54 55 56 57
#endif
	{ },
};

58 59
DECLARE_GLOBAL_DATA_PTR;

60
#ifdef HAVE_BLOCK_DEVICE
61
static block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
62 63
{
	const struct block_drvr *drvr = block_drvr;
64
	block_dev_desc_t* (*reloc_get_dev)(int dev);
65
	int (*select_hwpart)(int dev_num, int hwpart);
66
	char *name;
67
	int ret;
68

69 70 71
	if (!ifname)
		return NULL;

72
	name = drvr->name;
73
#ifdef CONFIG_NEEDS_MANUAL_RELOC
74 75
	name += gd->reloc_off;
#endif
76
	while (drvr->name) {
77
		name = drvr->name;
78
		reloc_get_dev = drvr->get_dev;
79
		select_hwpart = drvr->select_hwpart;
80
#ifdef CONFIG_NEEDS_MANUAL_RELOC
81
		name += gd->reloc_off;
82
		reloc_get_dev += gd->reloc_off;
83 84
		if (select_hwpart)
			select_hwpart += gd->reloc_off;
85
#endif
86 87 88 89
		if (strncmp(ifname, name, strlen(name)) == 0) {
			block_dev_desc_t *dev_desc = reloc_get_dev(dev);
			if (!dev_desc)
				return NULL;
90
			if (hwpart == 0 && !select_hwpart)
91 92 93 94 95 96 97 98
				return dev_desc;
			if (!select_hwpart)
				return NULL;
			ret = select_hwpart(dev_desc->dev, hwpart);
			if (ret < 0)
				return NULL;
			return dev_desc;
		}
99 100 101 102
		drvr++;
	}
	return NULL;
}
103 104 105

block_dev_desc_t *get_dev(const char *ifname, int dev)
{
106
	return get_dev_hwpart(ifname, dev, 0);
107
}
108
#else
109 110 111 112 113
block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
	return NULL;
}

114
block_dev_desc_t *get_dev(const char *ifname, int dev)
115 116 117 118 119
{
	return NULL;
}
#endif

120
#ifdef HAVE_BLOCK_DEVICE
W
wdenk 已提交
121 122 123 124 125

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

127
#ifdef CONFIG_LBA48
128
typedef uint64_t lba512_t;
W
wdenk 已提交
129
#else
130
typedef lbaint_t lba512_t;
W
wdenk 已提交
131
#endif
W
wdenk 已提交
132

133 134 135 136
/*
 * Overflowless variant of (block_count * mul_by / div_by)
 * when div_by > mul_by
 */
P
Pavel Machek 已提交
137
static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by)
138 139 140 141 142 143 144 145 146 147 148 149 150
{
	lba512_t bc_quot, bc_rem;

	/* x * m / d == x / d * m + (x % d) * m / d */
	bc_quot = block_count / div_by;
	bc_rem  = block_count - div_by * bc_quot;
	return bc_quot * mul_by + (bc_rem * mul_by) / div_by;
}

void dev_print (block_dev_desc_t *dev_desc)
{
	lba512_t lba512; /* number of blocks if 512bytes block size */

151 152 153 154 155
	if (dev_desc->type == DEV_TYPE_UNKNOWN) {
		puts ("not available\n");
		return;
	}

156
	switch (dev_desc->if_type) {
157 158 159
	case IF_TYPE_SCSI:
		printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
			dev_desc->target,dev_desc->lun,
W
wdenk 已提交
160
			dev_desc->vendor,
161 162 163
			dev_desc->product,
			dev_desc->revision);
		break;
164
	case IF_TYPE_ATAPI:
165 166
	case IF_TYPE_IDE:
	case IF_TYPE_SATA:
167 168 169 170
		printf ("Model: %s Firm: %s Ser#: %s\n",
			dev_desc->vendor,
			dev_desc->revision,
			dev_desc->product);
171
		break;
172 173
	case IF_TYPE_SD:
	case IF_TYPE_MMC:
174 175 176 177 178 179
	case IF_TYPE_USB:
		printf ("Vendor: %s Rev: %s Prod: %s\n",
			dev_desc->vendor,
			dev_desc->revision,
			dev_desc->product);
		break;
180 181 182
	case IF_TYPE_DOC:
		puts("device type DOC\n");
		return;
183
	case IF_TYPE_UNKNOWN:
184 185
		puts("device type unknown\n");
		return;
186
	default:
187
		printf("Unhandled device type: %i\n", dev_desc->if_type);
188
		return;
W
wdenk 已提交
189 190 191 192 193
	}
	puts ("            Type: ");
	if (dev_desc->removable)
		puts ("Removable ");
	switch (dev_desc->type & 0x1F) {
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
	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;
W
wdenk 已提交
209 210
	}
	puts ("\n");
211
	if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
W
wdenk 已提交
212
		ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
W
wdenk 已提交
213
		lbaint_t lba;
W
wdenk 已提交
214 215

		lba = dev_desc->lba;
W
wdenk 已提交
216

W
wdenk 已提交
217
		lba512 = (lba * (dev_desc->blksz/512));
W
wdenk 已提交
218
		/* round to 1 digit */
P
Pavel Machek 已提交
219 220
		/* 2048 = (1024 * 1024) / 512 MB */
		mb = lba512_muldiv(lba512, 10, 2048);
221

W
wdenk 已提交
222 223 224 225 226 227
		mb_quot	= mb / 10;
		mb_rem	= mb - (10 * mb_quot);

		gb = mb / 1024;
		gb_quot	= gb / 10;
		gb_rem	= gb - (10 * gb_quot);
228
#ifdef CONFIG_LBA48
W
wdenk 已提交
229
		if (dev_desc->lba48)
W
wdenk 已提交
230 231
			printf ("            Supports 48-bit addressing\n");
#endif
232
#if defined(CONFIG_SYS_64BIT_LBA)
233
		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
W
wdenk 已提交
234 235 236 237 238
			mb_quot, mb_rem,
			gb_quot, gb_rem,
			lba,
			dev_desc->blksz);
#else
W
wdenk 已提交
239 240 241
		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
			mb_quot, mb_rem,
			gb_quot, gb_rem,
W
wdenk 已提交
242
			(ulong)lba,
W
wdenk 已提交
243
			dev_desc->blksz);
W
wdenk 已提交
244
#endif
W
wdenk 已提交
245 246 247 248
	} else {
		puts ("            Capacity: not available\n");
	}
}
249
#endif
W
wdenk 已提交
250

251
#ifdef HAVE_BLOCK_DEVICE
W
wdenk 已提交
252

P
Pavel Machek 已提交
253
void init_part(block_dev_desc_t *dev_desc)
W
wdenk 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
{
#ifdef CONFIG_ISO_PARTITION
	if (test_part_iso(dev_desc) == 0) {
		dev_desc->part_type = PART_TYPE_ISO;
		return;
	}
#endif

#ifdef CONFIG_MAC_PARTITION
	if (test_part_mac(dev_desc) == 0) {
		dev_desc->part_type = PART_TYPE_MAC;
		return;
	}
#endif

269 270 271 272 273 274 275 276
/* must be placed before DOS partition detection */
#ifdef CONFIG_EFI_PARTITION
	if (test_part_efi(dev_desc) == 0) {
		dev_desc->part_type = PART_TYPE_EFI;
		return;
	}
#endif

W
wdenk 已提交
277 278 279 280 281 282
#ifdef CONFIG_DOS_PARTITION
	if (test_part_dos(dev_desc) == 0) {
		dev_desc->part_type = PART_TYPE_DOS;
		return;
	}
#endif
W
wdenk 已提交
283 284 285 286 287 288 289

#ifdef CONFIG_AMIGA_PARTITION
	if (test_part_amiga(dev_desc) == 0) {
	    dev_desc->part_type = PART_TYPE_AMIGA;
	    return;
	}
#endif
290
	dev_desc->part_type = PART_TYPE_UNKNOWN;
W
wdenk 已提交
291 292 293
}


294 295 296 297 298 299
#if defined(CONFIG_MAC_PARTITION) || \
	defined(CONFIG_DOS_PARTITION) || \
	defined(CONFIG_ISO_PARTITION) || \
	defined(CONFIG_AMIGA_PARTITION) || \
	defined(CONFIG_EFI_PARTITION)

P
Pavel Machek 已提交
300
static void print_part_header(const char *type, block_dev_desc_t *dev_desc)
W
wdenk 已提交
301 302 303
{
	puts ("\nPartition Map for ");
	switch (dev_desc->if_type) {
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	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;
L
Lei Wen 已提交
322 323 324
	case IF_TYPE_MMC:
		puts ("MMC");
		break;
325 326 327
	case IF_TYPE_HOST:
		puts("HOST");
		break;
328 329 330
	default:
		puts ("UNKNOWN");
		break;
W
wdenk 已提交
331 332 333 334 335
	}
	printf (" device %d  --   Partition Type: %s\n\n",
			dev_desc->dev, type);
}

336 337
#endif /* any CONFIG_..._PARTITION */

P
Pavel Machek 已提交
338
void print_part(block_dev_desc_t * dev_desc)
W
wdenk 已提交
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
{

		switch (dev_desc->part_type) {
#ifdef CONFIG_MAC_PARTITION
	case PART_TYPE_MAC:
		PRINTF ("## Testing for valid MAC partition ##\n");
		print_part_header ("MAC", dev_desc);
		print_part_mac (dev_desc);
		return;
#endif
#ifdef CONFIG_DOS_PARTITION
	case PART_TYPE_DOS:
		PRINTF ("## Testing for valid DOS partition ##\n");
		print_part_header ("DOS", dev_desc);
		print_part_dos (dev_desc);
		return;
#endif

#ifdef CONFIG_ISO_PARTITION
	case PART_TYPE_ISO:
		PRINTF ("## Testing for valid ISO Boot partition ##\n");
		print_part_header ("ISO", dev_desc);
		print_part_iso (dev_desc);
		return;
#endif
W
wdenk 已提交
364 365 366 367 368 369 370 371

#ifdef CONFIG_AMIGA_PARTITION
	case PART_TYPE_AMIGA:
	    PRINTF ("## Testing for a valid Amiga partition ##\n");
	    print_part_header ("AMIGA", dev_desc);
	    print_part_amiga (dev_desc);
	    return;
#endif
372 373 374 375 376 377 378 379

#ifdef CONFIG_EFI_PARTITION
	case PART_TYPE_EFI:
		PRINTF ("## Testing for valid EFI partition ##\n");
		print_part_header ("EFI", dev_desc);
		print_part_efi (dev_desc);
		return;
#endif
W
wdenk 已提交
380 381 382 383
	}
	puts ("## Unknown partition table\n");
}

384
#endif /* HAVE_BLOCK_DEVICE */
385

P
Pavel Machek 已提交
386 387
int get_partition_info(block_dev_desc_t *dev_desc, int part,
		       disk_partition_t *info)
388
{
389
#ifdef HAVE_BLOCK_DEVICE
390

391 392 393 394 395
#ifdef CONFIG_PARTITION_UUIDS
	/* The common case is no UUID support */
	info->uuid[0] = 0;
#endif

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
	switch (dev_desc->part_type) {
#ifdef CONFIG_MAC_PARTITION
	case PART_TYPE_MAC:
		if (get_partition_info_mac(dev_desc, part, info) == 0) {
			PRINTF("## Valid MAC partition found ##\n");
			return 0;
		}
		break;
#endif

#ifdef CONFIG_DOS_PARTITION
	case PART_TYPE_DOS:
		if (get_partition_info_dos(dev_desc, part, info) == 0) {
			PRINTF("## Valid DOS partition found ##\n");
			return 0;
		}
		break;
#endif

#ifdef CONFIG_ISO_PARTITION
	case PART_TYPE_ISO:
		if (get_partition_info_iso(dev_desc, part, info) == 0) {
			PRINTF("## Valid ISO boot partition found ##\n");
			return 0;
		}
		break;
#endif

#ifdef CONFIG_AMIGA_PARTITION
	case PART_TYPE_AMIGA:
		if (get_partition_info_amiga(dev_desc, part, info) == 0) {
			PRINTF("## Valid Amiga partition found ##\n");
			return 0;
		}
		break;
#endif

#ifdef CONFIG_EFI_PARTITION
	case PART_TYPE_EFI:
		if (get_partition_info_efi(dev_desc, part, info) == 0) {
			PRINTF("## Valid EFI partition found ##\n");
			return 0;
		}
		break;
#endif
	default:
		break;
	}
444
#endif /* HAVE_BLOCK_DEVICE */
445 446 447

	return -1;
}
448

449
int get_device(const char *ifname, const char *dev_hwpart_str,
S
Stephen Warren 已提交
450 451 452
	       block_dev_desc_t **dev_desc)
{
	char *ep;
453 454 455 456 457 458 459 460 461 462 463 464
	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;
465
		hwpart = 0;
466
	}
S
Stephen Warren 已提交
467 468 469 470 471

	dev = simple_strtoul(dev_str, &ep, 16);
	if (*ep) {
		printf("** Bad device specification %s %s **\n",
		       ifname, dev_str);
472 473 474 475 476 477 478 479 480 481 482 483
		dev = -1;
		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);
			dev = -1;
			goto cleanup;
		}
S
Stephen Warren 已提交
484 485
	}

486
	*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
S
Stephen Warren 已提交
487
	if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
488 489 490
		printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
		dev = -1;
		goto cleanup;
S
Stephen Warren 已提交
491 492
	}

493 494
cleanup:
	free(dup_str);
S
Stephen Warren 已提交
495 496 497
	return dev;
}

498 499 500 501
#define PART_UNSPECIFIED -2
#define PART_AUTO -1
#define MAX_SEARCH_PARTITIONS 16
int get_device_and_partition(const char *ifname, const char *dev_part_str,
502
			     block_dev_desc_t **dev_desc,
503
			     disk_partition_t *info, int allow_whole_dev)
504
{
505 506 507 508
	int ret = -1;
	const char *part_str;
	char *dup_str = NULL;
	const char *dev_str;
509
	int dev;
510 511 512 513 514
	char *ep;
	int p;
	int part;
	disk_partition_t tmpinfo;

H
Hans de Goede 已提交
515 516 517 518
#if defined CONFIG_SANDBOX && defined CONFIG_CMD_UBIFS
#error Only one of CONFIG_SANDBOX and CONFIG_CMD_UBIFS may be selected
#endif

519
#ifdef CONFIG_SANDBOX
520
	/*
P
Pavel Machek 已提交
521
	 * Special-case a pseudo block device "hostfs", to allow access to the
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
	 * 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");
#ifdef CONFIG_PARTITION_UUIDS
		info->uuid[0] = 0;
#endif

		return 0;
	}
538
#endif
539

H
Hans de Goede 已提交
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
#ifdef CONFIG_CMD_UBIFS
	/*
	 * Special-case ubi, ubi goes through a mtd, rathen then through
	 * 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");
#ifdef CONFIG_PARTITION_UUIDS
		info->uuid[0] = 0;
#endif
		return 0;
	}
#endif

562
	/* If no dev_part_str, use bootdevice environment variable */
563 564
	if (!dev_part_str || !strlen(dev_part_str) ||
	    !strcmp(dev_part_str, "-"))
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
		dev_part_str = getenv("bootdevice");

	/* 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;
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
	/* Look up the device */
	dev = get_device(ifname, dev_str, dev_desc);
	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;
		}
619

620 621 622 623 624 625 626 627 628
		/*
		 * 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;
629
		}
630

631 632
		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);

633
		info->start = 0;
634 635 636
		info->size = (*dev_desc)->lba;
		info->blksz = (*dev_desc)->blksz;
		info->bootable = 0;
637 638
		strcpy((char *)info->type, BOOT_PART_TYPE);
		strcpy((char *)info->name, "Whole Disk");
639 640 641
#ifdef CONFIG_PARTITION_UUIDS
		info->uuid[0] = 0;
#endif
642

643 644
		ret = 0;
		goto cleanup;
645 646
	}

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
	/*
	 * 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) {
		ret = get_partition_info(*dev_desc, part, info);
		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++) {
			ret = get_partition_info(*dev_desc, p, info);
			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");
704
			ret = -1;
705 706
			goto cleanup;
		}
707 708 709 710 711
	}
	if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
		printf("** Invalid partition type \"%.32s\""
			" (expect \"" BOOT_PART_TYPE "\")\n",
			info->type);
712 713
		ret  = -1;
		goto cleanup;
714 715
	}

716 717
	(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);

718 719
	ret = part;
	goto cleanup;
720

721 722 723
cleanup:
	free(dup_str);
	return ret;
724
}