如何在Linux中使用libudev以编程方式列出USB大容量存储设备?

时间:2014-08-18 10:21:17

标签: c++ c linux user-interface linux-kernel

我正在使用linux中的大容量存储设备进行项目。我正在尝试编写一个应用程序,它将列出所有连接的USB大容量存储设备,并在插入新的大容量存储设备时发出通知。我正在使用libudev来实现此目的。我使用了“http://www.signal11.us/oss/udev/”中的代码。我在这里做了修改

  /* 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);

现在的问题是它列出了所有的块设备。我只想要usb大容量存储设备。如何获取此列表。另一个问题是如何使用libudev获取USB存储设备的标签。

1 个答案:

答案 0 :(得分:11)

一种解决方案是使用以下标准匹配设备:

  • SUBSYSTEM ==“scsi”,DEVTYPE ==“scsi_device”
  • 子设备存在SUBSYSTEM ==“block”
  • 子设备与SUBSYSTEM ==“scsi_disk”
  • 一起存在
  • 父设备存在SUBSYSTEM ==“usb”,DEVTYPE ==“usb_device”

以下是示例程序(也可用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;
}

它是我外部磁盘的输出:

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