I want to get a ID_MODEL
and ID_VENDOR
properties of a USB device in Linux. I know its /dev/bus/usb/xxx/yyy
path.
I can do it with this code that depends on systemd (cc -lsystemd test.c
):
#include <assert.h>
#include <stdio.h>
#include <systemd/sd-device.h>
int main() {
sd_device* dev;
// This function is used in udevadm too.
// That means udevadm depends on systemd.
int r = sd_device_new_from_path(&dev, "/dev/bus/usb/xxx/yyy");
assert(r >= 0);
const char* val;
sd_device_get_property_value(dev, "ID_MODEL", &val);
printf("ID_MODEL: %s\n", val);
}
Output:
ID_MODEL: Android
However, my application should work on OpenRC-based distributions (like Atrix or Gentoo). Because of that the systemd dependency is not acceptable for me.
How can I get this information without it?
I would like a solution that does not rely on parsing lsusb
output.
libusb
Can you depend on libusb
? There is a similar question and answer over on the Linux and Unix StackExchange, with this sample code:
#include <stdio.h>
#include <usb.h>
main(){
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next)
for (dev = bus->devices; dev; dev = dev->next){
printf("Trying device %s/%s\n", bus->dirname, dev->filename);
printf("\tID_VENDOR = 0x%04x\n", dev->descriptor.idVendor);
printf("\tID_PRODUCT = 0x%04x\n", dev->descriptor.idProduct);
}
}
udevadm info
If you can use udev
there is a different lsusb
-like approach that may point you in the right direction. Using this answer from the Linux and Unix StackExchange, the udevadm
program may help. First, get the 'raw' device path:
$ udevadm info -q path -n /dev/usb/hiddev0
/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.6/1-4.6:1.0/usbmisc/hiddev0
And then you can query it:
$ udevadm info [-q <type>] -p /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.6/1-4.6:1.0/usbmisc/hiddev0
I don't have any actual USB devices to show you the output, but type
can be one of: name, symlink, path, property, or all. You would have to parse the output, but it is relatively easy given output resembling:
P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.6/1-5.6:1.0/usbmisc/hiddev1
N: usb/hiddev1
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.6/1-5.6:1.0/usbmisc/hiddev1
E: DEVNAME=/dev/usb/hiddev1
E: MAJOR=180
E: MINOR=1
E: SUBSYSTEM=usbmisc
In your C code you'd have to popen()
the commands and parse them like you're reading a file. Unfortunately if you want to operate at an even-lower level I'd have to suggest looking to the source code for udevadm
.
udev
?As you mentioned, a while ago systemd did take over udev development; I forget exactly when that happened. However, this udev fork from pavlinux was created that does not depend on systemd. It may also be helpful. The file src/udev-builtin-usb_id.c
is parsing vendor information so maybe that's a better route?
I'm making an assumption that this is simply a copy of udev before the integration with systemd, but I cannot attest to that. You may feel more comfortable checking out an older version of udev before the integration happened.