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