简体   繁体   中英

how to list USB mass storage devices programatically using libudev in Linux?

I am doing a project with mass storage devices in linux. I am trying to write an application which will list all the connected usb mass storage devices and will give notification when a new mass storage device is plugged in. I am using libudev for this purpose. I have used the code found in " http://www.signal11.us/oss/udev/ " . I have done the modification here

  /* Create a list of the devices in the 'block' subsystem. */
  enumerate = udev_enumerate_new(udev);
  udev_enumerate_add_match_subsystem(enumerate, "block");
  udev_enumerate_scan_devices(enumerate);
  devices = udev_enumerate_get_list_entry(enumerate);

The problem now is that it list all the block devices. I want only the usb mass storage devices. How to get this list. One more problem is that how to get the label of usb storage devices using libudev.

One solution is to match devices with the following criteria:

  • SUBSYSTEM == "scsi", DEVTYPE == "scsi_device"
  • child device exists with SUBSYSTEM == "block"
  • child device exists with SUBSYSTEM == "scsi_disk"
  • parent device exists with SUBSYSTEM == "usb", DEVTYPE == "usb_device"

Here is example program (also available on github ):

#include <libudev.h>
#include <stdio.h>

static struct udev_device*
get_child(
     struct udev* udev, struct udev_device* parent, const char* subsystem)
{
  struct udev_device* child = NULL;
  struct udev_enumerate *enumerate = udev_enumerate_new(udev);

  udev_enumerate_add_match_parent(enumerate, parent);
  udev_enumerate_add_match_subsystem(enumerate, subsystem);
  udev_enumerate_scan_devices(enumerate);

  struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
  struct udev_list_entry *entry;

  udev_list_entry_foreach(entry, devices) {
    const char *path = udev_list_entry_get_name(entry);
    child = udev_device_new_from_syspath(udev, path);
    break;
  }

  udev_enumerate_unref(enumerate);
  return child;
}

static void enumerate_usb_mass_storage(struct udev* udev)
{
  struct udev_enumerate* enumerate = udev_enumerate_new(udev);

  udev_enumerate_add_match_subsystem(enumerate, "scsi");
  udev_enumerate_add_match_property(enumerate, "DEVTYPE", "scsi_device");
  udev_enumerate_scan_devices(enumerate);

  struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
  struct udev_list_entry *entry;

  udev_list_entry_foreach(entry, devices) {
    const char* path = udev_list_entry_get_name(entry);
    struct udev_device* scsi = udev_device_new_from_syspath(udev, path);

    struct udev_device* block = get_child(udev, scsi, "block");
    struct udev_device* scsi_disk = get_child(udev, scsi, "scsi_disk");

    struct udev_device* usb
      = udev_device_get_parent_with_subsystem_devtype(
          scsi, "usb", "usb_device");

    if (block && scsi_disk && usb) {
        printf("block = %s, usb = %s:%s, scsi = %s\n",
          udev_device_get_devnode(block),
          udev_device_get_sysattr_value(usb, "idVendor"),
          udev_device_get_sysattr_value(usb, "idProduct"),
          udev_device_get_sysattr_value(scsi, "vendor"));
    }

    if (block)
      udev_device_unref(block);

    if (scsi_disk)
      udev_device_unref(scsi_disk);

    udev_device_unref(scsi);
  }

  udev_enumerate_unref(enumerate);
}

int main()
{
  struct udev* udev = udev_new();

  enumerate_usb_mass_storage(udev);

  udev_unref(udev);
  return 0;
}

And it's output for my external disk:

block = /dev/sdb, usb = 0bc2:ab20, scsi = Seagate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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