I was wondering what to do in the case where there are multiple devices with the same vendor:product IDs.
I tried running udevadm info -a /dev/sde
, which "walks up the chain of parent devices" (whatever that means?). By matching "ATTRS{devnum}" and "ATTRS{busnum}" with the Bus X Device Y output of lsusb
, I could see that not only did the udevadm listing produce the bus and device numbers for the USB hard drive as a "parent" of the block device /dev/sde
, but also the bus and device numbers of the hub it was connected to as well as the host controller! That could be useful if you want to identify a device by the port it's connected to.
I was a bit confused about why it seems so hard to get the USB device corresponding to a given block device, and I guess this clears that up a bit: the devices are not the same, there is a kind of filial relationship between the two.
Udevadm gives the paths of each parent, so you have some idea how to locate the correct parent by trimming the child path:
$ udevadm info --path=$(udevadm info -q path /dev/sde | cut -d / -f 1-7)
P: /devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4
N: bus/usb/002/024
E: BUSNUM=002
E: DEVNAME=/dev/bus/usb/002/024
E: DEVNUM=024
E: DEVPATH=/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4
E: DEVTYPE=usb_device
E: DRIVER=usb
E: ID_BUS=usb
E: ID_MODEL=External_HDD
....
We can pass the DEVNAME to lsusb:
$ lsusb -D $(udevadm info --path=$(udevadm info -q path /dev/sde
| cut -d / -f 1-7) | grep DEVNAME | cut -d = -f 2)
Device: ID 1058:0705 Western Digital Technologies, Inc. My Passport Elite (WDML)
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
...
So we can use this to tell that, for example, /dev/sde is connected as a USB 2.0 device (from the bcdUSB line above).
I'm not sure if this answers your question, but it gives a way to identify USB devices from block devices. Also it is not quite complete because I think you'll have to give a different argument to 'cut' if you don't have a hub in-between the controller and the device. Probably I should be counting from the end of the device path, rather than the beginning, but I couldn't find a way to pass a numeric argument to dirname
.
Update: Here is a solution that uses zsh to trim components from the end of the device path, let me know if it works for you:
$ cat usb-device-from-block-device
#!/bin/zsh
udevadm info --path ${${$(udevadm info -q path $1)}%/*/*/*/*/*/*} | grep DEVNAME | cut -d = -f 2
# Example:
$ usb-device-from-block-device /dev/sdc
/dev/bus/usb/001/017
$ lsusb -D $(usb-device-from-block-device /dev/sdc)
...