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