Linux下的USB驱动序列号C ++

有没有什么办法确定使用C + +的Linux的USB驱动器的S / N?

如果不是C ++有没有其他方式与hwinfo -diskhdparm -i

我将尝试总结一下我在linux上存储驱动序列号检索的经验。
我假设你想要的存储设备身份的序列号(按照SCSI规范)而不是USB设备的序列号(根据设备描述符下的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查询命令进行检索。 Linux中的一个可以读取VPD的commad工具是sdparm :

 > yum install sdparm > sdparm --quiet --page=sn /dev/sda Unit serial number VPD page: 3BT1ZQGR000081240XP7 

请注意,不是所有的设备都有这个序列号,市场充斥着哗众取宠,有些USB闪存盘会返回奇怪的序列号(例如我的sandisk cruzer只返回字母“u”)。 为了克服这个问题,有些人选择通过混合来自VPD的不同字符串(如Product ID,Vendor ID和Serial Number)来创建一个唯一的标识符。

代码在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); } } 

而这段代码将得到USB序列号…它不像clyfe那样技术上令人印象深刻,但是它似乎每次都有所掠夺。

 #include <unistd.h> #include <string.h> #include <stdio.h> int main(int arg, char **argv) { ssize_t len; char buf[256], *p; char buf2[256]; int i; len = readlink("/sys/block/sdb", buf, 256); buf[len] = 0; // printf("%s\n", buf); sprintf(buf2, "%s/%s", "/sys/block/", buf); for (i=0; i<6; i++) { p = strrchr(buf2, '/'); *p = 0; } // printf("%s\n", buf2); strcat(buf2, "/serial"); // printf("opening %s\n", buf2); int f = open(buf2, 0); len = read(f, buf, 256); if (len <= 0) { perror("read()"); } buf[len] = 0; printf("serial: %s\n", buf); } 

我发现了一些对你来说也很有趣的东西:

“ 如何检测/ dev / *是否是USB设备?

最好的办法可能是做命令行工具(可能也是):检查/proc/sys的相关文件,但是从C ++代码中检查。