简体   繁体   English

如何将 /proc/bus/usb/devices 条目映射到 /dev/sdX 设备?

[英]How to map /proc/bus/usb/devices entry to a /dev/sdX device?

I need to know how I can figure out to which entry in /proc/bus/usb/devices a /dev/sdX device maps to.我需要知道如何确定 /dev/sdX 设备映射到 /proc/bus/usb/devices 中的哪个条目。 Basically, I need to know the vendor id and product id of a given USB stick (which may not have a serial number).基本上,我需要知道给定 USB 记忆棒(可能没有序列号)的供应商 ID 和产品 ID。

In my case, I have this entry for my flash drive in /proc/bus/usb/devices:就我而言,我的闪存驱动器在 /proc/bus/usb/devices 中有这个条目:

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  6 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=0781 ProdID=5530 Rev= 2.00
S:  Manufacturer=SanDisk
S:  Product=Cruzer
S:  SerialNumber=0765400A1BD05BEE
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=200mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms

I happen to know that in my case it is /dev/sda, but I'm not sure how I can figure this out in code.我碰巧知道在我的情况下它是 /dev/sda,但我不确定如何在代码中解决这个问题。 My first approach was to loop through all /dev/sdXX devices and issue a SCSI_IOCTL_GET_BUS_NUMBER and/or SCSI_IOCTL_GET_IDLUN request, but the information returned doesn't help me match it up:我的第一种方法是遍历所有 /dev/sdXX 设备并发出 SCSI_IOCTL_GET_BUS_NUMBER 和/或 SCSI_IOCTL_GET_IDLUN 请求,但返回的信息并不能帮助我进行匹配:

/tmp # ./getscsiinfo /dev/sda
SCSI bus number: 8
ID: 00
LUN: 00
Channel: 00
Host#: 08
four_in_one: 08000000
host_unique_id: 0

I'm not sure how I can use the SCSI bus number or the ID, LUN, Channel, Host to map it to the entry in /proc/bus/usb/devices.我不确定如何使用 SCSI 总线编号或 ID、LUN、通道、主机将其映射到 /proc/bus/usb/devices 中的条目。 Or how I could get the SCSI bus number from the /proc/bus/usb/001/006 device, which is a usbfs device and doesn't appear to like the same ioctl's:或者我如何从 /proc/bus/usb/001/006 设备获取 SCSI 总线编号,这是一个 usbfs 设备并且似乎不喜欢相同的 ioctl:

/tmp # ./getscsiinfo /proc/bus/usb/001/006
Could not get bus number: Inappropriate ioctl for device

Here's the test code for my little getscsiinfo test tool:这是我的小getscsiinfo测试工具的测试代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>

struct scsi_idlun
{
    int four_in_one;
    int host_unique_id;
};

int main(int argc, char** argv) {
    if (argc != 2)
        return 1;

    int fd = open(argv[1], O_RDONLY | O_NONBLOCK);
    if (fd < 0)
    {
        printf("Error opening device: %m\n");
        return 1;
    }

    int busNumber = -1;
    if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &busNumber) < 0)
    {
        printf("Could not get bus number: %m\n");
        close(fd);
        return 1;
    }

    printf("SCSI bus number: %d\n", busNumber);

    struct scsi_idlun argid;
    if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, &argid) < 0)
    {
        printf("Could not get id: %m\n");
        close(fd);
        return 1;
    }

    printf("ID: %02x\n", argid.four_in_one & 0xFF);
    printf("LUN: %02x\n", (argid.four_in_one >> 8) & 0xFF);
    printf("Channel: %02x\n", (argid.four_in_one >> 16) & 0xFF);
    printf("Host#: %02x\n", (argid.four_in_one >> 24) & 0xFF);
    printf("four_in_one: %08x\n", (unsigned int)argid.four_in_one);
    printf("host_unique_id: %d\n", argid.host_unique_id);

    close(fd);
    return 0;
}

Does anyone have any idea?有人有什么主意吗?

I believe you can collect such information using libudev library.我相信您可以使用 libudev 库收集此类信息。

Here are some details about it: http://www.signal11.us/oss/udev/以下是有关它的一些详细信息: http : //www.signal11.us/oss/udev/

I found something like this on above site:我在上面的网站上找到了这样的东西:

.. Using libudev, we'll be able to inspect the devices, including their Vendor ID (VID), Product ID (PID), serial number, and device strings, without ever opening the device. .. 使用 libudev,我们将能够检查设备,包括它们的供应商 ID (VID)、产品 ID (PID)、序列号和设备字符串,而无需打开设备。 Further, libudev will tell us exactly where inside /dev the device's node is located, giving the application a robust and distribution-independent way of accessing the device.此外,libudev 会告诉我们设备节点在 /dev 内部的确切位置,为应用程序提供了一种访问设备的强大且与分发无关的方式。 ... ...

udevadm is capable of what your are trying to achieve. udevadm能够完成您想要实现的目标。

udevadm info -a -p $(udevadm info -q path -n /dev/sda)

udevadm 's sources will tell you how it is done. udevadm的来源将告诉您它是如何完成的。

This isn't all that easy, nor very well documented (at least from a high-level perspective).这不是那么容易,也不是很好的文档(至少从高级角度来看)。 The following should work in Kernel's from version 3.1 upward (at least).以下应该在 3.1 版以上的内核中工作(至少)。

I have found the easiest (probably not the only way) is to navigate from the block device entry and test each block device until you find the one that matches your USB entry.我发现最简单的(可能不是唯一的)方法是从块设备条目导航并测试每个块设备,直到找到与您的 USB 条目匹配的块设备。

For example, given a block device in /sys/block , such as sdb , you can find the hardware device descriptor entry like this:例如,给定/sys/block的块设备,例如sdb ,您可以像这样找到硬件设备描述符条目:

# cd /sys/block
# cd $(readlink sdb); cd ../../../../../..
# ls -l
total 0
drwxr-xr-x 6 root root     0 Aug 14 10:47 1-1:1.0
-rw-r--r-- 1 root root  4096 Aug 14 10:52 authorized
-rw-r--r-- 1 root root  4096 Aug 14 10:52 avoid_reset_quirk
-r--r--r-- 1 root root  4096 Aug 14 10:47 bcdDevice
-rw-r--r-- 1 root root  4096 Aug 14 10:49 bConfigurationValue
-r--r--r-- 1 root root  4096 Aug 14 10:47 bDeviceClass
-r--r--r-- 1 root root  4096 Aug 14 10:49 bDeviceProtocol
-r--r--r-- 1 root root  4096 Aug 14 10:49 bDeviceSubClass
-r--r--r-- 1 root root  4096 Aug 14 10:49 bmAttributes
-r--r--r-- 1 root root  4096 Aug 14 10:49 bMaxPacketSize0
-r--r--r-- 1 root root  4096 Aug 14 10:49 bMaxPower
-r--r--r-- 1 root root  4096 Aug 14 10:49 bNumConfigurations
-r--r--r-- 1 root root  4096 Aug 14 10:49 bNumInterfaces
-r--r--r-- 1 root root  4096 Aug 14 10:49 busnum
-r--r--r-- 1 root root  4096 Aug 14 10:52 configuration
-r--r--r-- 1 root root 65553 Aug 14 10:47 descriptors
-r--r--r-- 1 root root  4096 Aug 14 10:52 dev
-r--r--r-- 1 root root  4096 Aug 14 10:49 devnum
-r--r--r-- 1 root root  4096 Aug 14 10:52 devpath
lrwxrwxrwx 1 root root     0 Aug 14 10:47 driver -> ../../../../../../bus/usb/drivers/usb
drwxr-xr-x 3 root root     0 Aug 14 10:52 ep_00
-r--r--r-- 1 root root  4096 Aug 14 10:47 idProduct
-r--r--r-- 1 root root  4096 Aug 14 10:47 idVendor
-r--r--r-- 1 root root  4096 Aug 14 10:52 ltm_capable
-r--r--r-- 1 root root  4096 Aug 14 10:47 manufacturer
-r--r--r-- 1 root root  4096 Aug 14 10:49 maxchild
lrwxrwxrwx 1 root root     0 Aug 14 10:52 port -> ../1-0:1.0/port1
drwxr-xr-x 2 root root     0 Aug 14 10:52 power
-r--r--r-- 1 root root  4096 Aug 14 10:47 product
-r--r--r-- 1 root root  4096 Aug 14 10:52 quirks
-r--r--r-- 1 root root  4096 Aug 14 10:47 removable
--w------- 1 root root  4096 Aug 14 10:52 remove
-r--r--r-- 1 root root  4096 Aug 14 10:47 serial
-r--r--r-- 1 root root  4096 Aug 14 10:49 speed
lrwxrwxrwx 1 root root     0 Aug 14 10:47 subsystem -> ../../../../../../bus/usb
-rw-r--r-- 1 root root  4096 Aug 14 10:47 uevent
-r--r--r-- 1 root root  4096 Aug 14 10:52 urbnum
-r--r--r-- 1 root root  4096 Aug 14 10:49 version

(You can find excellent documentation for the contents of the USB Descriptor here on the BeyondLogic site. ) (您可以在 BeyondLogic 站点上找到有关 USB 描述符内容的优秀文档

Given the above, you should be able to map one or more of the USB device fields to the contents of /proc/bus/usb/devices .鉴于上述情况,您应该能够将一个或多个 USB 设备字段映射到/proc/bus/usb/devices I find that the serial number is the easiest to match on, so that if you were to cat serial above, you would get the same serial number as listed:我发现,序列号是最容易匹配,因此,如果你是cat serial上面,你会得到相同的序列号列:

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=0781 ProdID=5575 Rev=01.26
S:  Manufacturer=SanDisk
S:  Product=Cruzer Glide
S:  SerialNumber=4C530100801115115112
C:  #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=200mA
I:  If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage

If you go to /sys/block , you can list the full path to the host device entry in the storage driver sysfs entry for each device.如果您转到/sys/block ,您可以在每个设备的存储驱动程序 sysfs 条目中列出主机设备条目的完整路径。 Typically, I do this using some programmatic means instead of at the shell prompt, but here you can see the links themselves:通常,我使用一些编程方式而不是在 shell 提示符下执行此操作,但在这里您可以看到链接本身:

# ls -l sd*
lrwxrwxrwx 1 root root 0 Aug 14 10:45 sda -> ../devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
lrwxrwxrwx 1 root root 0 Aug 14 10:47 sdb -> ../devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host33/target33:0:0/33:0:0:0/block/sdb

Note that you mustn't make any assumptions about the numbers you see in the links.请注意,您不得对链接中看到的数字做出任何假设。 Depending upon the bus subsystem, the mappings could be quite different.根据总线子系统的不同,映射可能会大不相同。 For example, on a Raspberry Pi, it looks like this:例如,在 Raspberry Pi 上,它看起来像这样:

# ls -l sd*
lrwxrwxrwx 1 root root 0 Aug 13 23:54 sda -> ../devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host3/target3:0:0/3:0:0:0/block/sda
lrwxrwxrwx 1 root root 0 Aug 13 23:54 sdb -> ../devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/host4/target4:0:0/4:0:0:0/block/sdb

So, the best approach is to take the approach listed at the top and navigate relative to the storage driver to find the USB device descriptor.因此,最好的方法是采用顶部列出的方法并相对于存储驱动程序导航以查找 USB 设备描述符。

I'd be curious about more authoritative answers to this.我很好奇对此的更权威的答案。 The method above was arrived at by trial-and-error but has been working on several different devices and Kernels with no problem.上面的方法是通过反复试验得出的,但已经在几种不同的设备和内核上工作,没有任何问题。

For anyone using a system without udev, this link has the exact answer you're looking for: 对于使用没有udev的系统的任何人,此链接具有您正在寻找的确切答案:

http://www.spinics.net/lists/linux-usb/msg60916.html http://www.spinics.net/lists/linux-usb/msg60916.html

Instead of using proc/bus/usb which is for usbfs you can use /proc/scsi/scsi.您可以使用 /proc/scsi/scsi,而不是使用用于 usbfs 的 proc/bus/usb。 In there you can find the Vendor and Serial number with specific channel ID and LUN number.在那里您可以找到带有特定通道 ID 和 LUN 编号的供应商和序列号。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM