1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2001
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 #include <common.h>
8 #include <blk.h>
9 #include <command.h>
10 #include <env.h>
11 #include <errno.h>
12 #include <ide.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <part.h>
16 #include <ubifs_uboot.h>
17 
18 #undef	PART_DEBUG
19 
20 #ifdef	PART_DEBUG
21 #define	PRINTF(fmt,args...)	printf (fmt ,##args)
22 #else
23 #define PRINTF(fmt,args...)
24 #endif
25 
26 /* Check all partition types */
27 #define PART_TYPE_ALL		-1
28 
part_driver_lookup_type(struct blk_desc * dev_desc)29 static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
30 {
31 	struct part_driver *drv =
32 		ll_entry_start(struct part_driver, part_driver);
33 	const int n_ents = ll_entry_count(struct part_driver, part_driver);
34 	struct part_driver *entry;
35 
36 	if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
37 		for (entry = drv; entry != drv + n_ents; entry++) {
38 			int ret;
39 
40 			ret = entry->test(dev_desc);
41 			if (!ret) {
42 				dev_desc->part_type = entry->part_type;
43 				return entry;
44 			}
45 		}
46 	} else {
47 		for (entry = drv; entry != drv + n_ents; entry++) {
48 			if (dev_desc->part_type == entry->part_type)
49 				return entry;
50 		}
51 	}
52 
53 	/* Not found */
54 	return NULL;
55 }
56 
get_dev_hwpart(const char * ifname,int dev,int hwpart)57 static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
58 {
59 	struct blk_desc *dev_desc;
60 	int ret;
61 
62 	if (!blk_enabled())
63 		return NULL;
64 	dev_desc = blk_get_devnum_by_uclass_idname(ifname, dev);
65 	if (!dev_desc) {
66 		debug("%s: No device for iface '%s', dev %d\n", __func__,
67 		      ifname, dev);
68 		return NULL;
69 	}
70 	ret = blk_dselect_hwpart(dev_desc, hwpart);
71 	if (ret) {
72 		debug("%s: Failed to select h/w partition: err-%d\n", __func__,
73 		      ret);
74 		return NULL;
75 	}
76 
77 	return dev_desc;
78 }
79 
blk_get_dev(const char * ifname,int dev)80 struct blk_desc *blk_get_dev(const char *ifname, int dev)
81 {
82 	if (!blk_enabled())
83 		return NULL;
84 
85 	return get_dev_hwpart(ifname, dev, 0);
86 }
87 
88 /* ------------------------------------------------------------------------- */
89 /*
90  * reports device info to the user
91  */
92 
93 #ifdef CONFIG_LBA48
94 typedef uint64_t lba512_t;
95 #else
96 typedef lbaint_t lba512_t;
97 #endif
98 
99 /*
100  * Overflowless variant of (block_count * mul_by / 2**right_shift)
101  * when 2**right_shift > mul_by
102  */
lba512_muldiv(lba512_t block_count,lba512_t mul_by,int right_shift)103 static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by,
104 			      int right_shift)
105 {
106 	lba512_t bc_quot, bc_rem;
107 
108 	/* x * m / d == x / d * m + (x % d) * m / d */
109 	bc_quot = block_count >> right_shift;
110 	bc_rem  = block_count - (bc_quot << right_shift);
111 	return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift);
112 }
113 
dev_print(struct blk_desc * dev_desc)114 void dev_print(struct blk_desc *dev_desc)
115 {
116 	lba512_t lba512; /* number of blocks if 512bytes block size */
117 
118 	if (dev_desc->type == DEV_TYPE_UNKNOWN) {
119 		puts ("not available\n");
120 		return;
121 	}
122 
123 	switch (dev_desc->uclass_id) {
124 	case UCLASS_SCSI:
125 		printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
126 			dev_desc->target,dev_desc->lun,
127 			dev_desc->vendor,
128 			dev_desc->product,
129 			dev_desc->revision);
130 		break;
131 	case UCLASS_IDE:
132 	case UCLASS_AHCI:
133 		printf ("Model: %s Firm: %s Ser#: %s\n",
134 			dev_desc->vendor,
135 			dev_desc->revision,
136 			dev_desc->product);
137 		break;
138 	case UCLASS_MMC:
139 	case UCLASS_USB:
140 	case UCLASS_NVME:
141 	case UCLASS_PVBLOCK:
142 	case UCLASS_HOST:
143 	case UCLASS_BLKMAP:
144 		printf ("Vendor: %s Rev: %s Prod: %s\n",
145 			dev_desc->vendor,
146 			dev_desc->revision,
147 			dev_desc->product);
148 		break;
149 	case UCLASS_VIRTIO:
150 		printf("%s VirtIO Block Device\n", dev_desc->vendor);
151 		break;
152 	case UCLASS_EFI_MEDIA:
153 		printf("EFI media Block Device %d\n", dev_desc->devnum);
154 		break;
155 	case UCLASS_INVALID:
156 		puts("device type unknown\n");
157 		return;
158 	default:
159 		printf("Unhandled device type: %i\n", dev_desc->uclass_id);
160 		return;
161 	}
162 	puts ("            Type: ");
163 	if (dev_desc->removable)
164 		puts ("Removable ");
165 	switch (dev_desc->type & 0x1F) {
166 	case DEV_TYPE_HARDDISK:
167 		puts ("Hard Disk");
168 		break;
169 	case DEV_TYPE_CDROM:
170 		puts ("CD ROM");
171 		break;
172 	case DEV_TYPE_OPDISK:
173 		puts ("Optical Device");
174 		break;
175 	case DEV_TYPE_TAPE:
176 		puts ("Tape");
177 		break;
178 	default:
179 		printf ("# %02X #", dev_desc->type & 0x1F);
180 		break;
181 	}
182 	puts ("\n");
183 	if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
184 		ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
185 		lbaint_t lba;
186 
187 		lba = dev_desc->lba;
188 
189 		lba512 = (lba * (dev_desc->blksz/512));
190 		/* round to 1 digit */
191 		/* 2048 = (1024 * 1024) / 512 MB */
192 		mb = lba512_muldiv(lba512, 10, 11);
193 
194 		mb_quot	= mb / 10;
195 		mb_rem	= mb - (10 * mb_quot);
196 
197 		gb = mb / 1024;
198 		gb_quot	= gb / 10;
199 		gb_rem	= gb - (10 * gb_quot);
200 #ifdef CONFIG_LBA48
201 		if (dev_desc->lba48)
202 			printf ("            Supports 48-bit addressing\n");
203 #endif
204 #if defined(CONFIG_SYS_64BIT_LBA)
205 		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
206 			mb_quot, mb_rem,
207 			gb_quot, gb_rem,
208 			lba,
209 			dev_desc->blksz);
210 #else
211 		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
212 			mb_quot, mb_rem,
213 			gb_quot, gb_rem,
214 			(ulong)lba,
215 			dev_desc->blksz);
216 #endif
217 	} else {
218 		puts ("            Capacity: not available\n");
219 	}
220 }
221 
part_init(struct blk_desc * dev_desc)222 void part_init(struct blk_desc *dev_desc)
223 {
224 	struct part_driver *drv =
225 		ll_entry_start(struct part_driver, part_driver);
226 	const int n_ents = ll_entry_count(struct part_driver, part_driver);
227 	struct part_driver *entry;
228 
229 	blkcache_invalidate(dev_desc->uclass_id, dev_desc->devnum);
230 
231 	dev_desc->part_type = PART_TYPE_UNKNOWN;
232 	for (entry = drv; entry != drv + n_ents; entry++) {
233 		int ret;
234 
235 		ret = entry->test(dev_desc);
236 		debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret);
237 		if (!ret) {
238 			dev_desc->part_type = entry->part_type;
239 			break;
240 		}
241 	}
242 }
243 
print_part_header(const char * type,struct blk_desc * dev_desc)244 static void print_part_header(const char *type, struct blk_desc *dev_desc)
245 {
246 #if CONFIG_IS_ENABLED(MAC_PARTITION) || \
247 	CONFIG_IS_ENABLED(DOS_PARTITION) || \
248 	CONFIG_IS_ENABLED(ISO_PARTITION) || \
249 	CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
250 	CONFIG_IS_ENABLED(EFI_PARTITION)
251 	puts ("\nPartition Map for ");
252 	switch (dev_desc->uclass_id) {
253 	case UCLASS_IDE:
254 		puts ("IDE");
255 		break;
256 	case UCLASS_AHCI:
257 		puts ("SATA");
258 		break;
259 	case UCLASS_SCSI:
260 		puts ("SCSI");
261 		break;
262 	case UCLASS_USB:
263 		puts ("USB");
264 		break;
265 	case UCLASS_MMC:
266 		puts ("MMC");
267 		break;
268 	case UCLASS_HOST:
269 		puts ("HOST");
270 		break;
271 	case UCLASS_NVME:
272 		puts ("NVMe");
273 		break;
274 	case UCLASS_PVBLOCK:
275 		puts("PV BLOCK");
276 		break;
277 	case UCLASS_VIRTIO:
278 		puts("VirtIO");
279 		break;
280 	case UCLASS_EFI_MEDIA:
281 		puts("EFI");
282 		break;
283 	default:
284 		puts("UNKNOWN");
285 		break;
286 	}
287 	printf (" device %d  --   Partition Type: %s\n\n",
288 			dev_desc->devnum, type);
289 #endif /* any CONFIG_..._PARTITION */
290 }
291 
part_print(struct blk_desc * dev_desc)292 void part_print(struct blk_desc *dev_desc)
293 {
294 	struct part_driver *drv;
295 
296 	drv = part_driver_lookup_type(dev_desc);
297 	if (!drv) {
298 		printf("## Unknown partition table type %x\n",
299 		       dev_desc->part_type);
300 		return;
301 	}
302 
303 	PRINTF("## Testing for valid %s partition ##\n", drv->name);
304 	print_part_header(drv->name, dev_desc);
305 	if (drv->print)
306 		drv->print(dev_desc);
307 }
308 
part_get_info(struct blk_desc * dev_desc,int part,struct disk_partition * info)309 int part_get_info(struct blk_desc *dev_desc, int part,
310 		       struct disk_partition *info)
311 {
312 	struct part_driver *drv;
313 
314 	if (blk_enabled()) {
315 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
316 		/* The common case is no UUID support */
317 		info->uuid[0] = 0;
318 #endif
319 #ifdef CONFIG_PARTITION_TYPE_GUID
320 		info->type_guid[0] = 0;
321 #endif
322 
323 		drv = part_driver_lookup_type(dev_desc);
324 		if (!drv) {
325 			debug("## Unknown partition table type %x\n",
326 			      dev_desc->part_type);
327 			return -EPROTONOSUPPORT;
328 		}
329 		if (!drv->get_info) {
330 			PRINTF("## Driver %s does not have the get_info() method\n",
331 			       drv->name);
332 			return -ENOSYS;
333 		}
334 		if (drv->get_info(dev_desc, part, info) == 0) {
335 			PRINTF("## Valid %s partition found ##\n", drv->name);
336 			return 0;
337 		}
338 	}
339 
340 	return -ENOENT;
341 }
342 
part_get_info_whole_disk(struct blk_desc * dev_desc,struct disk_partition * info)343 int part_get_info_whole_disk(struct blk_desc *dev_desc,
344 			     struct disk_partition *info)
345 {
346 	info->start = 0;
347 	info->size = dev_desc->lba;
348 	info->blksz = dev_desc->blksz;
349 	info->bootable = 0;
350 	strcpy((char *)info->type, BOOT_PART_TYPE);
351 	strcpy((char *)info->name, "Whole Disk");
352 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
353 	info->uuid[0] = 0;
354 #endif
355 #ifdef CONFIG_PARTITION_TYPE_GUID
356 	info->type_guid[0] = 0;
357 #endif
358 
359 	return 0;
360 }
361 
blk_get_device_by_str(const char * ifname,const char * dev_hwpart_str,struct blk_desc ** dev_desc)362 int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
363 			  struct blk_desc **dev_desc)
364 {
365 	char *ep;
366 	char *dup_str = NULL;
367 	const char *dev_str, *hwpart_str;
368 	int dev, hwpart;
369 
370 	hwpart_str = strchr(dev_hwpart_str, '.');
371 	if (hwpart_str) {
372 		dup_str = strdup(dev_hwpart_str);
373 		dup_str[hwpart_str - dev_hwpart_str] = 0;
374 		dev_str = dup_str;
375 		hwpart_str++;
376 	} else {
377 		dev_str = dev_hwpart_str;
378 		hwpart = 0;
379 	}
380 
381 	dev = hextoul(dev_str, &ep);
382 	if (*ep) {
383 		printf("** Bad device specification %s %s **\n",
384 		       ifname, dev_str);
385 		dev = -EINVAL;
386 		goto cleanup;
387 	}
388 
389 	if (hwpart_str) {
390 		hwpart = hextoul(hwpart_str, &ep);
391 		if (*ep) {
392 			printf("** Bad HW partition specification %s %s **\n",
393 			    ifname, hwpart_str);
394 			dev = -EINVAL;
395 			goto cleanup;
396 		}
397 	}
398 
399 	*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
400 	if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
401 		debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
402 		dev = -ENODEV;
403 		goto cleanup;
404 	}
405 
406 	if (blk_enabled()) {
407 		/*
408 		 * Updates the partition table for the specified hw partition.
409 		 * Always should be done, otherwise hw partition 0 will return
410 		 * stale data after displaying a non-zero hw partition.
411 		 */
412 		if ((*dev_desc)->uclass_id == UCLASS_MMC)
413 			part_init(*dev_desc);
414 	}
415 
416 cleanup:
417 	free(dup_str);
418 	return dev;
419 }
420 
421 #define PART_UNSPECIFIED -2
422 #define PART_AUTO -1
blk_get_device_part_str(const char * ifname,const char * dev_part_str,struct blk_desc ** dev_desc,struct disk_partition * info,int allow_whole_dev)423 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
424 			     struct blk_desc **dev_desc,
425 			     struct disk_partition *info, int allow_whole_dev)
426 {
427 	int ret;
428 	const char *part_str;
429 	char *dup_str = NULL;
430 	const char *dev_str;
431 	int dev;
432 	char *ep;
433 	int p;
434 	int part;
435 	struct disk_partition tmpinfo;
436 
437 	*dev_desc = NULL;
438 	memset(info, 0, sizeof(*info));
439 
440 #if IS_ENABLED(CONFIG_SANDBOX) || IS_ENABLED(CONFIG_SEMIHOSTING)
441 	/*
442 	 * Special-case a pseudo block device "hostfs", to allow access to the
443 	 * host's own filesystem.
444 	 */
445 	if (!strcmp(ifname, "hostfs")) {
446 		strcpy((char *)info->type, BOOT_PART_TYPE);
447 		strcpy((char *)info->name, "Host filesystem");
448 
449 		return 0;
450 	}
451 #endif
452 
453 #if IS_ENABLED(CONFIG_CMD_UBIFS) && !IS_ENABLED(CONFIG_SPL_BUILD)
454 	/*
455 	 * Special-case ubi, ubi goes through a mtd, rather than through
456 	 * a regular block device.
457 	 */
458 	if (!strcmp(ifname, "ubi")) {
459 		if (!ubifs_is_mounted()) {
460 			printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
461 			return -EINVAL;
462 		}
463 
464 		strcpy((char *)info->type, BOOT_PART_TYPE);
465 		strcpy((char *)info->name, "UBI");
466 		return 0;
467 	}
468 #endif
469 
470 	/* If no dev_part_str, use bootdevice environment variable */
471 	if (!dev_part_str || !strlen(dev_part_str) ||
472 	    !strcmp(dev_part_str, "-"))
473 		dev_part_str = env_get("bootdevice");
474 
475 	/* If still no dev_part_str, it's an error */
476 	if (!dev_part_str) {
477 		printf("** No device specified **\n");
478 		ret = -ENODEV;
479 		goto cleanup;
480 	}
481 
482 	/* Separate device and partition ID specification */
483 	part_str = strchr(dev_part_str, ':');
484 	if (part_str) {
485 		dup_str = strdup(dev_part_str);
486 		dup_str[part_str - dev_part_str] = 0;
487 		dev_str = dup_str;
488 		part_str++;
489 	} else {
490 		dev_str = dev_part_str;
491 	}
492 
493 	/* Look up the device */
494 	dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
495 	if (dev < 0) {
496 		printf("** Bad device specification %s %s **\n",
497 		       ifname, dev_str);
498 		ret = dev;
499 		goto cleanup;
500 	}
501 
502 	/* Convert partition ID string to number */
503 	if (!part_str || !*part_str) {
504 		part = PART_UNSPECIFIED;
505 	} else if (!strcmp(part_str, "auto")) {
506 		part = PART_AUTO;
507 	} else {
508 		/* Something specified -> use exactly that */
509 		part = (int)hextoul(part_str, &ep);
510 		/*
511 		 * Less than whole string converted,
512 		 * or request for whole device, but caller requires partition.
513 		 */
514 		if (*ep || (part == 0 && !allow_whole_dev)) {
515 			printf("** Bad partition specification %s %s **\n",
516 			    ifname, dev_part_str);
517 			ret = -ENOENT;
518 			goto cleanup;
519 		}
520 	}
521 
522 	/*
523 	 * No partition table on device,
524 	 * or user requested partition 0 (entire device).
525 	 */
526 	if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
527 	    (part == 0)) {
528 		if (!(*dev_desc)->lba) {
529 			printf("** Bad device size - %s %s **\n", ifname,
530 			       dev_str);
531 			ret = -EINVAL;
532 			goto cleanup;
533 		}
534 
535 		/*
536 		 * If user specified a partition ID other than 0,
537 		 * or the calling command only accepts partitions,
538 		 * it's an error.
539 		 */
540 		if ((part > 0) || (!allow_whole_dev)) {
541 			printf("** No partition table - %s %s **\n", ifname,
542 			       dev_str);
543 			ret = -EPROTONOSUPPORT;
544 			goto cleanup;
545 		}
546 
547 		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
548 
549 		part_get_info_whole_disk(*dev_desc, info);
550 
551 		ret = 0;
552 		goto cleanup;
553 	}
554 
555 	/*
556 	 * Now there's known to be a partition table,
557 	 * not specifying a partition means to pick partition 1.
558 	 */
559 	if (part == PART_UNSPECIFIED)
560 		part = 1;
561 
562 	/*
563 	 * If user didn't specify a partition number, or did specify something
564 	 * other than "auto", use that partition number directly.
565 	 */
566 	if (part != PART_AUTO) {
567 		ret = part_get_info(*dev_desc, part, info);
568 		if (ret) {
569 			printf("** Invalid partition %d **\n", part);
570 			goto cleanup;
571 		}
572 	} else {
573 		/*
574 		 * Find the first bootable partition.
575 		 * If none are bootable, fall back to the first valid partition.
576 		 */
577 		part = 0;
578 		for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
579 			ret = part_get_info(*dev_desc, p, info);
580 			if (ret)
581 				continue;
582 
583 			/*
584 			 * First valid partition, or new better partition?
585 			 * If so, save partition ID.
586 			 */
587 			if (!part || info->bootable)
588 				part = p;
589 
590 			/* Best possible partition? Stop searching. */
591 			if (info->bootable)
592 				break;
593 
594 			/*
595 			 * We now need to search further for best possible.
596 			 * If we what we just queried was the best so far,
597 			 * save the info since we over-write it next loop.
598 			 */
599 			if (part == p)
600 				tmpinfo = *info;
601 		}
602 		/* If we found any acceptable partition */
603 		if (part) {
604 			/*
605 			 * If we searched all possible partition IDs,
606 			 * return the first valid partition we found.
607 			 */
608 			if (p == MAX_SEARCH_PARTITIONS + 1)
609 				*info = tmpinfo;
610 		} else {
611 			printf("** No valid partitions found **\n");
612 			goto cleanup;
613 		}
614 	}
615 	if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
616 		printf("** Invalid partition type \"%.32s\""
617 			" (expect \"" BOOT_PART_TYPE "\")\n",
618 			info->type);
619 		ret  = -EINVAL;
620 		goto cleanup;
621 	}
622 
623 	(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
624 
625 	ret = part;
626 	goto cleanup;
627 
628 cleanup:
629 	free(dup_str);
630 	return ret;
631 }
632 
part_get_info_by_name_type(struct blk_desc * dev_desc,const char * name,struct disk_partition * info,int part_type)633 int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
634 			       struct disk_partition *info, int part_type)
635 {
636 	struct part_driver *part_drv;
637 	int ret;
638 	int i;
639 
640 	part_drv = part_driver_lookup_type(dev_desc);
641 	if (!part_drv)
642 		return -1;
643 
644 	if (!part_drv->get_info) {
645 		log_debug("## Driver %s does not have the get_info() method\n",
646 			  part_drv->name);
647 		return -ENOSYS;
648 	}
649 
650 	for (i = 1; i < part_drv->max_entries; i++) {
651 		ret = part_drv->get_info(dev_desc, i, info);
652 		if (ret != 0) {
653 			/* no more entries in table */
654 			break;
655 		}
656 		if (strcmp(name, (const char *)info->name) == 0) {
657 			/* matched */
658 			return i;
659 		}
660 	}
661 
662 	return -ENOENT;
663 }
664 
part_get_info_by_name(struct blk_desc * dev_desc,const char * name,struct disk_partition * info)665 int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
666 			  struct disk_partition *info)
667 {
668 	return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
669 }
670 
671 /**
672  * Get partition info from device number and partition name.
673  *
674  * Parse a device number and partition name string in the form of
675  * "devicenum.hwpartnum#partition_name", for example "0.1#misc". devicenum and
676  * hwpartnum are both optional, defaulting to 0. If the partition is found,
677  * sets dev_desc and part_info accordingly with the information of the
678  * partition with the given partition_name.
679  *
680  * @param[in] dev_iface Device interface
681  * @param[in] dev_part_str Input string argument, like "0.1#misc"
682  * @param[out] dev_desc Place to store the device description pointer
683  * @param[out] part_info Place to store the partition information
684  * Return: 0 on success, or a negative on error
685  */
part_get_info_by_dev_and_name(const char * dev_iface,const char * dev_part_str,struct blk_desc ** dev_desc,struct disk_partition * part_info)686 static int part_get_info_by_dev_and_name(const char *dev_iface,
687 					 const char *dev_part_str,
688 					 struct blk_desc **dev_desc,
689 					 struct disk_partition *part_info)
690 {
691 	char *dup_str = NULL;
692 	const char *dev_str, *part_str;
693 	int ret;
694 
695 	/* Separate device and partition name specification */
696 	if (dev_part_str)
697 		part_str = strchr(dev_part_str, '#');
698 	else
699 		part_str = NULL;
700 
701 	if (part_str) {
702 		dup_str = strdup(dev_part_str);
703 		dup_str[part_str - dev_part_str] = 0;
704 		dev_str = dup_str;
705 		part_str++;
706 	} else {
707 		return -EINVAL;
708 	}
709 
710 	ret = blk_get_device_by_str(dev_iface, dev_str, dev_desc);
711 	if (ret < 0)
712 		goto cleanup;
713 
714 	ret = part_get_info_by_name(*dev_desc, part_str, part_info);
715 	if (ret < 0)
716 		printf("Could not find \"%s\" partition\n", part_str);
717 
718 cleanup:
719 	free(dup_str);
720 	return ret;
721 }
722 
part_get_info_by_dev_and_name_or_num(const char * dev_iface,const char * dev_part_str,struct blk_desc ** dev_desc,struct disk_partition * part_info,int allow_whole_dev)723 int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
724 					 const char *dev_part_str,
725 					 struct blk_desc **dev_desc,
726 					 struct disk_partition *part_info,
727 					 int allow_whole_dev)
728 {
729 	int ret;
730 
731 	/* Split the part_name if passed as "$dev_num#part_name". */
732 	ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str,
733 					    dev_desc, part_info);
734 	if (ret >= 0)
735 		return ret;
736 	/*
737 	 * Couldn't lookup by name, try looking up the partition description
738 	 * directly.
739 	 */
740 	ret = blk_get_device_part_str(dev_iface, dev_part_str,
741 				      dev_desc, part_info, allow_whole_dev);
742 	if (ret < 0)
743 		printf("Couldn't find partition %s %s\n",
744 		       dev_iface, dev_part_str);
745 	return ret;
746 }
747 
part_set_generic_name(const struct blk_desc * dev_desc,int part_num,char * name)748 void part_set_generic_name(const struct blk_desc *dev_desc,
749 	int part_num, char *name)
750 {
751 	char *devtype;
752 
753 	switch (dev_desc->uclass_id) {
754 	case UCLASS_IDE:
755 	case UCLASS_AHCI:
756 		devtype = "hd";
757 		break;
758 	case UCLASS_SCSI:
759 		devtype = "sd";
760 		break;
761 	case UCLASS_USB:
762 		devtype = "usbd";
763 		break;
764 	case UCLASS_MMC:
765 		devtype = "mmcsd";
766 		break;
767 	default:
768 		devtype = "xx";
769 		break;
770 	}
771 
772 	sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
773 }
774 
part_get_bootable(struct blk_desc * desc)775 int part_get_bootable(struct blk_desc *desc)
776 {
777 	struct disk_partition info;
778 	int p;
779 
780 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
781 		int ret;
782 
783 		ret = part_get_info(desc, p, &info);
784 		if (!ret && info.bootable)
785 			return p;
786 	}
787 
788 	return 0;
789 }
790