如何在linux中获取USB连接硬盘串口?

时间:2014-03-13 07:53:27

标签: c linux

我需要在外部安装的硬盘中创建一个文件.created文件应该包含硬盘的序列号,并且该文件可以被其他进程使用。

我尝试使用以下代码

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>

int main(int argc, char *argv[])
{
   static struct hd_driveid hd;
   int fd;

   if (geteuid() >  0) {
    printf("ERROR: Must be root to use\n");
    exit(1);
    }

   if ((fd = open(argv[1], O_RDONLY|O_NONBLOCK)) < 0) {
    printf("ERROR: Cannot open device %s\n", argv[1]);
    exit(1);
    }

   if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
    printf("Hard Disk Model: %.40s\n", hd.model);
    printf("  Serial Number: %.20s\n", hd.serial_no);
    } else if (errno == -ENOMSG) {
      printf("No hard disk identification information available\n");
    } else {
     perror("ERROR: HDIO_GET_IDENTITY");
     exit(1);
   }

   exit(0);
}

这对内部硬盘工作正常,但是当我为外部硬盘(usb)执行此操作时,它会给我以下错误

ERROR: HDIO_GET_IDENTITY: Invalid argument

2 个答案:

答案 0 :(得分:2)

由于设备已连接到USB网桥,因此无法发送HDIO_GET_IDENTITY命令。 您可以尝试hdparm来查询设备的身份。使用默认选项时,hdparm无法识别设备,因此您必须使用-d指定设备类型(请参阅USB devices and smartmontools)。

如果没有-d选项,我会得到:

$ sudo smartctl /dev/sdc
/dev/sdc: Unknown USB bridge [0x059f:0x1011 (0x000)]
Please specify device type with the -d option.

使用-d sat,autohdparm会设法显示有关设备的一些信息:

$ sudo smartctl -d sat,auto -i /dev/sdc
/dev/sdc [SCSI]: Device open changed type from 'sat,auto' to 'scsi'
=== START OF INFORMATION SECTION ===
Vendor:               ST2000VN
Product:              000-1H3164
User Capacity:        2 000 398 934 016 bytes [2,00 TB]
Logical block size:   512 bytes
Device type:          disk
Local Time is:        Thu Mar 13 09:41:32 2014 CET
SMART support is:     Unavailable - device lacks SMART capability.

您可以尝试在C程序中执行与smartctl相同的操作,但编写调用smartctl的脚本可能更容易。

答案 1 :(得分:1)

感谢您的解释,我得到以下内容以识别外部硬盘的序列号

#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;
}

void trim(char * s) {
    char * p = s;
    int l = strlen(p);

    while(isspace(p[l - 1])) p[--l] = 0;
    while(* p && isspace(* p)) ++p, --l;

    memmove(s, p, l + 1);
}

int storeData (char *filepath, char *data) {
    int rc = 0;

    FILE *fOut = fopen (filepath, "a");
    if (fOut != NULL) {
        if (fputs (data, fOut) != EOF) {
            rc = 1;
        }
        fclose (fOut); // or for the paranoid: if (fclose (fOut) == EOF) rc = 0;
    }

    return rc;
}

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

    if(argc>1){
    char *dev = (char *)argv[1];
    char outStr[1024];

    printf("\nEntered Serial no : %s\n",argv[1]);
    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]);
    scsi_serial[4+scsi_serial[3]]='\0';
    trim(&scsi_serial[4]);
    sprintf(outStr,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> \n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\"> \n<properties>\n<comment/>\n<entry key=\"SerialNo\">%s</entry>\n</properties>\n", (char *) & scsi_serial[4]);
    //strcat((char *)argv[2],(char *)"/hdd.xml");
    printf("\n%s",outStr);
//  printf("\n%s",(char *)argv[2]);
    //storeData((char *)argv[1],(char *) outStr);

    } 

close(fd);


}else{

printf("\nInsufficient no of arguments \n");
}

    return (EXIT_SUCCESS);


}