4

I need to know how I can figure out to which entry in /proc/bus/usb/devices a /dev/sdX device maps to. Basically, I need to know the vendor id and product id of a given USB stick (which may not have a serial number).

In my case, I have this entry for my flash drive in /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. 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:

/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. 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:

/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:

#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?

4

4 に答える 4

2

udevadmあなたが達成しようとしていることが可能です。

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

udevadmのソースは、それがどのように行われるかを教えてくれます。

于 2012-05-19T12:23:18.723 に答える
2

libudev ライブラリを使用すると、そのような情報を収集できると思います。

詳細は次のとおりです。 http://www.signal11.us/oss/udev/

上記のサイトでこんなものを見つけました。

.. libudev を使用すると、デバイスを開かなくても、ベンダー ID (VID)、製品 ID (PID)、シリアル番号、デバイス文字列などのデバイスを検査できます。さらに、libudev はデバイスのノードが /dev 内のどこにあるかを正確に教えてくれるので、アプリケーションは堅牢でディストリビューションに依存しない方法でデバイスにアクセスできます。...

于 2012-05-18T14:14:28.377 に答える
1

これはそれほど簡単ではなく、十分に文書化されているわけでもありません (少なくとも大まかな観点からは)。以下は、バージョン 3.1 以降のカーネルで (少なくとも) 動作するはずです。

最も簡単な方法 (おそらく唯一の方法ではない) は、ブロック デバイス エントリから移動し、USB エントリに一致するデバイスが見つかるまで各ブロック デバイスをテストすることです。

たとえば/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

( BeyondLogic サイトで、USB 記述子の内容に関する優れたドキュメントを見つけることができます。 )

上記を考えると、1 つ以上の USB デバイス フィールドを の内容にマップできるはずです/proc/bus/usb/devices。シリアル番号が最も照合しやすいことがわかりました。したがって、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

にアクセスすると/sys/block、各デバイスのストレージ ドライバの sysfs エントリにあるホスト デバイス エントリへのフル パスを一覧表示できます。通常、これはシェル プロンプトではなく、プログラムによる手段を使用して行いますが、ここではリンク自体を確認できます。

# 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

リンクに表示されている数字について、いかなる仮定もしてはならないことに注意してください。バス サブシステムによっては、マッピングがまったく異なる場合があります。たとえば、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

したがって、最善の方法は、上部にリストされている方法を使用して、ストレージ ドライバーを基準にして移動し、USB デバイス記述子を見つけることです。

これに対するより信頼できる回答に興味があります。上記の方法は試行錯誤の末にたどり着いたものですが、いくつかの異なるデバイスとカーネルで問題なく動作しています。

于 2016-08-14T01:15:03.683 に答える