linux c语言获取usb设备号,Linux C ++下的USB驱动器序列号

小编典典

我将尝试总结有关在Linux上进行存储驱动器序列号检索的经验。

我假设您要 存储设备 标识的序列号(按照SCSI规范)而不是 USB设备 的序列号(按照Device

Descriptor下的USB规范),这两个是不同的实体。

注意!

大多数设备倾向于在USB控制器中实现序列号,而内部SCSI磁盘的序列号未实现。

因此,如果要唯一地标识USB设备,最好的方法是从设备描述符(USB规范)创建字符串,例如

VendorId-ProductId-HardwareRevision-SerialNumber

。在下面,我将描述如何检索存储驱动器的SN ,按要求。

驱动器分为两类(实际上更多,但让我们简化一下):类ATA(hda,hdb …)和类SCSI(sda sdb …)。USB驱动器属于第二类,它们称为

SCSI连接磁盘

。在这两种情况下,都可以使用ioctl调用来检索所需的信息(在我们的情况下为序列号)。

对于 SCSI设备(包括USB驱动器)

,Linux通用驱动程序及其API记录在tldp上。

SCSI设备上的序列号可在重要产品数据(简称:VPD)中找到,并且可以使用SCSI查询命令检索。sdparm是linux中一个可获取此VPD的通用实用程序:

> yum install sdparm

> sdparm --quiet --page=sn /dev/sda

Unit serial number VPD page:

3BT1ZQGR000081240XP7

请注意,并非所有设备都具有该序列号,市场上充斥着廉价的仿冒品,一些USB闪存盘返回了奇怪的序列号(例如,我的s​​andisk cruzer仅返回字母“

u”)。为了克服这个问题,有人选择通过混合来自VPD的不同字符串(例如产品ID,供应商ID和序列号)来创建唯一标识符。

C中的代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

int scsi_get_serial(int fd, void *buf, size_t buf_len) {

// we shall retrieve page 0x80 as per http://en.wikipedia.org/wiki/SCSI_Inquiry_Command

unsigned char inq_cmd[] = {INQUIRY, 1, 0x80, 0, buf_len, 0};

unsigned char sense[32];

struct sg_io_hdr io_hdr;

int result;

memset(&io_hdr, 0, sizeof (io_hdr));

io_hdr.interface_id = 'S';

io_hdr.cmdp = inq_cmd;

io_hdr.cmd_len = sizeof (inq_cmd);

io_hdr.dxferp = buf;

io_hdr.dxfer_len = buf_len;

io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;

io_hdr.sbp = sense;

io_hdr.mx_sb_len = sizeof (sense);

io_hdr.timeout = 5000;

result = ioctl(fd, SG_IO, &io_hdr);

if (result < 0)

return result;

if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)

return 1;

return 0;

}

int main(int argc, char** argv) {

char *dev = "/dev/sda";

char scsi_serial[255];

int rc;

int fd;

fd = open(dev, O_RDONLY | O_NONBLOCK);

if (fd < 0) {

perror(dev);

}

memset(scsi_serial, 0, sizeof (scsi_serial));

rc = scsi_get_serial(fd, scsi_serial, 255);

// scsi_serial[3] is the length of the serial number

// scsi_serial[4] is serial number (raw, NOT null terminated)

if (rc < 0) {

printf("FAIL, rc=%d, errno=%d\n", rc, errno);

} else

if (rc == 1) {

printf("FAIL, rc=%d, drive doesn't report serial number\n", rc);

} else {

if (!scsi_serial[3]) {

printf("Failed to retrieve serial for %s\n", dev);

return -1;

}

printf("Serial Number: %.*s\n", (size_t) scsi_serial[3], (char *) & scsi_serial[4]);

}

close(fd);

return (EXIT_SUCCESS);

}

为了完善起见,我还将提供代码以检索 ATA设备 的序列号(hda,hdb …)。这不适用于USB设备。

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(){

struct hd_driveid *id;

char *dev = "/dev/hda";

int fd;

fd = open(dev, O_RDONLY|O_NONBLOCK);

if(fd < 0) {

perror("cannot open");

}

if (ioctl(fd, HDIO_GET_IDENTITY, id) < 0) {

close(fd);

perror("ioctl error");

} else {

// if we want to retrieve only for removable drives use this branching

if ((id->config & (1 << 7)) || (id->command_set_1 & 4)) {

close(fd);

printf("Serial Number: %s\n", id->serial_no);

} else {

perror("support not removable");

}

close(fd);

}

}

2020-06-07

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值