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

6

我正在使用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存储设备的标签。


看一下父设备。 - CL.
@CL。您能否解释一下...我已经使用了在http://www.signal11.us/oss/udev/找到的代码。 - jsaji
你尝试在那个页面中搜索“parent”了吗? - CL.
1个回答

11

一种解决方案是匹配具有以下标准的设备:

  • SUBSYSTEM == "scsi",DEVTYPE == "scsi_device"
  • 存在具有 SUBSYSTEM == "block" 的子设备
  • 存在具有 SUBSYSTEM == "scsi_disk" 的子设备
  • 存在具有 SUBSYSTEM == "usb",DEVTYPE == "usb_device" 的父设备

这里有一个示例程序(也可在 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

我遇到了以下错误: "udev_enumerate_add_match_parent"未在此范围内声明。 - Ravi Bhushan
@RaviBhushan,我猜你的libudev版本比较旧。这个函数是在udev-174中首次出现的。 - gavv
1
一旦我使用 udev_enumerate_add_match_parent,valgrind 就会抱怨有内存泄漏。 - Th. Thielemann
@Th.Thielemann,使用这个片段无法复现。您能否发布您的代码? - gavv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接