有什么方法可以确定使用C ++的linux中USB驱动器的s / n吗?
如果不是的话,C ++是否与hwinfo -diskand 有任何其他区别hdparm -i?
hwinfo -disk
hdparm -i
我将尝试总结有关在Linux上进行存储驱动器序列号检索的经验。 我假设您要 存储设备 标识的序列号(按照SCSI规范)而不是 USB设备 的序列号(按照Device Descriptor下的USB规范),这两个是不同的实体。
注意! 大多数设备倾向于在USB控制器中实现序列号,而内部SCSI磁盘的序列号未实现。 因此,如果要唯一地标识USB设备,最好的方法是从设备描述符(USB规范)创建字符串,例如 VendorId-ProductId-HardwareRevision-SerialNumber 。在下面,我将描述如何检索存储驱动器的SN ,按要求。
注意! 大多数设备倾向于在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闪存盘返回了奇怪的序列号(例如,我的sandisk cruzer仅返回字母“ u”)。为了克服这个问题,有人选择通过混合来自VPD的不同字符串(例如产品ID,供应商ID和序列号)来创建唯一标识符。
C中的代码:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <scsi/scsi.h> #include <scsi/sg.h> #include <sys/ioctl.h> 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 <stdlib.h> #include <stdio.h> #include <sys/ioctl.h> #include <linux/hdreg.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <cctype> #include <unistd.h> 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); } }