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        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
 235void 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
 257static 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
 308void 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
 327int 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
 361int 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
 380int 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 = hextoul(dev_str, &ep);
 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 = hextoul(hwpart_str, &ep);
 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
 433cleanup:
 434        free(dup_str);
 435        return dev;
 436}
 437
 438#define PART_UNSPECIFIED -2
 439#define PART_AUTO -1
 440int 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)hextoul(part_str, &ep);
 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
 656cleanup:
 657        free(dup_str);
 658        return ret;
 659}
 660
 661int 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
 686int 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 */
 707static 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        if (dev_part_str)
 718                part_str = strchr(dev_part_str, '#');
 719        else
 720                part_str = NULL;
 721
 722        if (part_str) {
 723                dup_str = strdup(dev_part_str);
 724                dup_str[part_str - dev_part_str] = 0;
 725                dev_str = dup_str;
 726                part_str++;
 727        } else {
 728                return -EINVAL;
 729        }
 730
 731        ret = blk_get_device_by_str(dev_iface, dev_str, dev_desc);
 732        if (ret < 0)
 733                goto cleanup;
 734
 735        ret = part_get_info_by_name(*dev_desc, part_str, part_info);
 736        if (ret < 0)
 737                printf("Could not find \"%s\" partition\n", part_str);
 738
 739cleanup:
 740        free(dup_str);
 741        return ret;
 742}
 743
 744int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
 745                                         const char *dev_part_str,
 746                                         struct blk_desc **dev_desc,
 747                                         struct disk_partition *part_info,
 748                                         int allow_whole_dev)
 749{
 750        int ret;
 751
 752        /* Split the part_name if passed as "$dev_num#part_name". */
 753        ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str,
 754                                            dev_desc, part_info);
 755        if (ret >= 0)
 756                return ret;
 757        /*
 758         * Couldn't lookup by name, try looking up the partition description
 759         * directly.
 760         */
 761        ret = blk_get_device_part_str(dev_iface, dev_part_str,
 762                                      dev_desc, part_info, allow_whole_dev);
 763        if (ret < 0)
 764                printf("Couldn't find partition %s %s\n",
 765                       dev_iface, dev_part_str);
 766        return ret;
 767}
 768
 769void part_set_generic_name(const struct blk_desc *dev_desc,
 770        int part_num, char *name)
 771{
 772        char *devtype;
 773
 774        switch (dev_desc->if_type) {
 775        case IF_TYPE_IDE:
 776        case IF_TYPE_SATA:
 777        case IF_TYPE_ATAPI:
 778                devtype = "hd";
 779                break;
 780        case IF_TYPE_SCSI:
 781                devtype = "sd";
 782                break;
 783        case IF_TYPE_USB:
 784                devtype = "usbd";
 785                break;
 786        case IF_TYPE_DOC:
 787                devtype = "docd";
 788                break;
 789        case IF_TYPE_MMC:
 790        case IF_TYPE_SD:
 791                devtype = "mmcsd";
 792                break;
 793        default:
 794                devtype = "xx";
 795                break;
 796        }
 797
 798        sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
 799}
 800