如何在 Linux 下的 C 中确定 USB 存储(USB 闪存驱动器)“设备路径”

Posted

技术标签:

【中文标题】如何在 Linux 下的 C 中确定 USB 存储(USB 闪存驱动器)“设备路径”【英文标题】:how to determine USB storage (USB flash drive) 'device path' in C under Linux 【发布时间】:2013-12-22 06:09:51 【问题描述】:

如何在 Linux 下使用 C 以编程方式枚举所有 USB 存储?我想获取诸如 '/dev/sdb4' 这样的字符串,以便我可以使用 mount() 来挂载它们。

我想有一些方法可以列出所有 USB 设备,但我只想要 USB 存储。

另外,我们能否区分U盘(直接插入机器的USB口)和U盘(通常通过USB线连接到机器)?

谢谢。

【问题讨论】:

查看lsusb 可能会帮助您列出 USB 设备。 【参考方案1】:

您可以从目录/proc/scsi/usb-storage 中找到所有 USB 存储设备。通过列出该目录的内容,您可以找到 SCSI 主机设备编号,然后您可以使用这些编号检查文件/sys/class/scsi_disk/N:*:*:*,其中 N 是 SCSI 主机设备的编号。 /sys/class/scsi_disk/ 中的文件是指向实际设备目录的链接。

以下是执行此操作的一种方法,尽管它不是最好的方法之一。我认为您可能希望依赖自动安装程序而不是手动编码。

根据您附加的特定磁盘设备(在您的示例中列出两个)进行混合和匹配的部分留给读者练习。

#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <libgen.h>
#include <linux/limits.h>
#include <glob.h>
#include <unistd.h>

#define PROC_USB_DEV "/proc/scsi/usb-storage"
#define SYS_SCSI_HOST "/sys/class/scsi_host/host%s/device"
#define SYS_SCSI_DEV "/sys/class/scsi_disk/%s:*"
#define SYS_SCSI_TGT "%s/device/block/*"

int main(int argc, char **argv) 
  DIR *dp = NULL;
  struct dirent *dt = NULL;

  if((dp = opendir(PROC_USB_DEV)) == NULL) 
    fprintf(stderr, "Can not open %s: %s", PROC_USB_DEV, strerror(errno)); 
    return 2;
  

  /* find usb storage device hosts which appear as scsi hosts */
  /* for the sake of example this one hasn't been done with glob(3) */
  while((dt = readdir(dp)) != NULL) 
    int scsi_dev = 0;
    /* skip '.' and '..', possibly others too */
    if((scsi_dev = atoi(basename(dt->d_name))) < 1) continue;

    char buf[PATH_MAX];
    char pat[PATH_MAX];

    snprintf(buf, PATH_MAX, SYS_SCSI_HOST, basename(dt->d_name));
    snprintf(pat, PATH_MAX, SYS_SCSI_DEV, basename(dt->d_name));

    glob_t hosts;
    size_t count;

    /* find SCSI host device paths */
    glob(pat, 0, 0, &hosts);
    if(hosts.gl_pathc > 0) 
      char **p;
      int n;
      for(p = hosts.gl_pathv, n = hosts.gl_pathc; n; p++, n--) 
        char tgtbuf[PATH_MAX + NAME_MAX];

        snprintf(tgtbuf, PATH_MAX + NAME_MAX, SYS_SCSI_TGT, *p);

        /* find SCSI disk device paths */
        glob_t devs;
        glob(tgtbuf, 0, 0, &devs);
        if(devs.gl_pathc > 0) 
          char **ptr;
          int c;
          for(ptr = devs.gl_pathv, c = devs.gl_pathc; c; ptr++, c--) 
            printf("We would now call mount(2) for /dev/%s.\n",
                   basename(*ptr));
          
        
        globfree(&devs);
      
      globfree(&hosts);
    
  

最后一点:就一般的编码风格而言,这很可能不是学习的最佳示例。

【讨论】:

这很有效,但 "SYS_SCSI_TGT "%s/device/block/*"" 在我的 CentOS 5.8 上似乎不正确。在我的机器上,没有 /sys/class/scsi_disk/4:0:0:0/device/block/ 目录;有一个 /sys/class/scsi_disk/4:0:0:0/device/block:sdb/ 目录,在该目录下有一个 'sdb4' 目录。我想'sdb4'就是我想要的东西,我可以从中派生'/dev/sdb4',然后将它传递给mount()。但是我不确定我的理解是否正确;你能澄清更多吗?而且,我在哪里可以找到有关这些文件路径的文档?谢谢。

以上是关于如何在 Linux 下的 C 中确定 USB 存储(USB 闪存驱动器)“设备路径”的主要内容,如果未能解决你的问题,请参考以下文章

linux系统下的USB口如何使用??

Linux usb子系统 _usb-skeleton.c精析

怎样写linux下的USB设备驱动程序

如何在 Linux 上使用 Ruby 实现实时 USB 存储检测?

linux 下的动态库制作 以及在python 中如何调用 c 函数库

怎样写linux下的USB设备驱动程序