user-0 提问: linux 获取硬盘序列号

回复:
user: user-0
content: 把三四方案中sudo去掉更合理

user: user-1
content: 磁盘序列号以前写过，也是加密用的，过于久远，忘记了就当我路过吧

user: user-2
content: 来看看，然后5分到手

user: user-3
content: 好法子。支持分享。

user: user-0
content: 代码写好，结贴

user: user-0
content: #include <cctype> #include <cstdlib> #include <cstring> #include <fcntl.h> #include <unistd.h> #include <scsi/sg.h> #include <sys/ioctl.h> #include <linux/hdreg.h> #include <string> #include <fstream>  static bool get_disk_name(std::string & disk_name) {     disk_name.c_str();      std::ifstream ifs("/etc/mtab", std::ios::binary);     if (!ifs.is_open())     {         return(false);     }      char line[4096] = { 0 };     while (!ifs.eof())     {         ifs.getline(line, sizeof(line));         if (!ifs.good())         {             break;         }          const char * disk = line;         while (isspace(disk[0]))         {             ++disk;         }          const char * space = strchr(disk, ' ');         if (NULL == space)         {             continue;         }          const char * mount = space + 1;         while (isspace(mount[0]))         {             ++mount;         }         if ('/' != mount[0] || ' ' != mount[1])         {             continue;         }          while (space > disk && isdigit(space[-1]))         {             --space;         }          if (space > disk)         {             std::string(disk, space).swap(disk_name);             break;         }     }      ifs.close();      return(!disk_name.empty()); }  static void trim_serial(const void * serial, size_t serial_len, std::string & serial_no) {     const char * serial_s = static_cast<const char *>(serial);     const char * serial_e = serial_s + serial_len;     while (serial_s < serial_e)     {         if (isspace(serial_s[0]))         {             ++serial_s;         }         else if ('\0' == serial_e[-1] || isspace(serial_e[-1]))         {             --serial_e;         }         else         {             break;         }     }      if (serial_s < serial_e)     {         std::string(serial_s, serial_e).swap(serial_no);     } }  static bool get_disk_serial_by_way_1(const std::string & disk_name, std::string & serial_no) {     serial_no.clear();      int fd = open(disk_name.c_str(), O_RDONLY);     if (-1 == fd)     {         return(false);     }      struct hd_driveid drive = { 0 };     if (0 == ioctl(fd, HDIO_GET_IDENTITY, &drive))     {         trim_serial(drive.serial_no, sizeof(drive.serial_no), serial_no);     }      close(fd);      return(!serial_no.empty()); }  static bool scsi_io(                 int fd, unsigned char * cdb,                  unsigned char cdb_size, int xfer_dir,                  unsigned char * data, unsigned int data_size,                  unsigned char * sense, unsigned int sense_len             ) {     sg_io_hdr_t io_hdr = { 0 };     io_hdr.interface_id = 'S';      /* CDB */     io_hdr.cmdp = cdb;     io_hdr.cmd_len = cdb_size;      /* Where to store the sense_data, if there was an error */     io_hdr.sbp = sense;     io_hdr.mx_sb_len = sense_len;      /*        Transfer direction, either in or out. Linux does not yet        support bidirectional SCSI transfers ?      */     io_hdr.dxfer_direction = xfer_dir;      /*        Where to store the DATA IN/OUT from the device and how big the        buffer is      */     io_hdr.dxferp = data;     io_hdr.dxfer_len = data_size;      /* SCSI timeout in ms */     io_hdr.timeout = 5000;      if (ioctl(fd, SG_IO, &io_hdr) < 0)     {         return(false);     }      /* now for the error processing */     if (SG_INFO_OK != (io_hdr.info & SG_INFO_OK_MASK) && io_hdr.sb_len_wr > 0)     {         return(false);     }      if (io_hdr.masked_status || io_hdr.host_status || io_hdr.driver_status)     {         return(false);     }      return(true); }  static bool get_disk_serial_by_way_2(const std::string & disk_name, std::string & serial_no) {     serial_no.clear();      int fd = open(disk_name.c_str(), O_RDONLY);     if (-1 == fd)     {         return(false);     }      int version = 0;     if (ioctl(fd, SG_GET_VERSION_NUM, &version) < 0 || version < 30000)     {         close(fd);         return(false);     }      const unsigned int data_size = 0x00ff;     unsigned char data[data_size] = { 0 };     const unsigned int sense_len = 32;     unsigned char sense[sense_len] = { 0 };     unsigned char cdb[] = { 0x12, 0x01, 0x80, 0x00, 0x00, 0x00 };     cdb[3] = (data_size >> 8) & 0xff;     cdb[4] = (data_size & 0xff);      if (scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, data_size, sense, sense_len))     {         /* Page Length */         int page_len = data[3];          /* Unit Serial Number */         trim_serial(data + 4, page_len, serial_no);     }      close(fd);      return(!serial_no.empty()); }  static bool parse_serial(const char * line, int line_size, const char * match_words, std::string & serial_no) {     const char * serial_s = strstr(line, match_words);     if (NULL == serial_s)     {         return(false);     }     serial_s += strlen(match_words);     while (isspace(serial_s[0]))     {         ++serial_s;     }      const char * serial_e = line + line_size;     const char * comma = strchr(serial_s, ',');     if (NULL != comma)     {         serial_e = comma;     }      while (serial_e > serial_s && isspace(serial_e[-1]))     {         --serial_e;     }      if (serial_e <= serial_s)     {         return(false);     }      std::string(serial_s, serial_e).swap(serial_no);      return(true); }  static void get_serial(const char * file_name, const char * match_words, std::string & serial_no) {     serial_no.c_str();      std::ifstream ifs(file_name, std::ios::binary);     if (!ifs.is_open())     {         return;     }      char line[4096] = { 0 };     while (!ifs.eof())     {         ifs.getline(line, sizeof(line));         if (!ifs.good())         {             break;         }          if (0 == ifs.gcount())         {             continue;         }          if (parse_serial(line, ifs.gcount() - 1, match_words, serial_no))         {             break;         }     }      ifs.close(); }  static bool get_disk_serial_by_way_3(const std::string & disk_name, std::string & serial_no) {     serial_no.c_str();      const char * hdparm_result = ".hdparm_result.txt";     char command[512] = { 0 };     snprintf(command, sizeof(command), "sudo hdparm -i %s | grep SerialNo > %s", disk_name.c_str(), hdparm_result);      if (0 == system(command))     {         get_serial(hdparm_result, "SerialNo=", serial_no);     }      unlink(hdparm_result);      return(!serial_no.empty()); }  static bool get_disk_serial_by_way_4(std::string & serial_no) {     serial_no.c_str();      const char * lshw_result = ".lshw_result.txt";     char command[512] = { 0 };     snprintf(command, sizeof(command), "sudo lshw -class disk | grep serial > %s", lshw_result);      if (0 == system(command))     {         get_serial(lshw_result, "serial:", serial_no);     }      unlink(lshw_result);      return(!serial_no.empty()); }  static bool get_disk_serial_number(std::string & serial_no) {     if (0 != getuid())     {         return(false);     }      std::string disk_name;     if (get_disk_name(disk_name))     {         if (get_disk_serial_by_way_1(disk_name, serial_no))         {             return(true);         }         if (get_disk_serial_by_way_2(disk_name, serial_no))         {             return(true);         }         if (get_disk_serial_by_way_3(disk_name, serial_no))         {             return(true);         }     }     if (get_disk_serial_by_way_4(serial_no))     {         return(true);     }     return(false); }  static void test_1() {     std::string serial_no;     if (get_disk_serial_number(serial_no))     {         printf("serial_number: [%s]\n", serial_no.c_str());     }     else     {         printf("get serial number failed\n");     } }  static void test_2() {     std::string disk_name;     if (get_disk_name(disk_name))     {         printf("disk_name:[%s]\n", disk_name.c_str());         {             std::string serial_no;             get_disk_serial_by_way_1(disk_name, serial_no);             printf("get_serial_by_way_1:[%s]\n", serial_no.c_str());         }         {             std::string serial_no;             get_disk_serial_by_way_2(disk_name, serial_no);             printf("get_serial_by_way_2:[%s]\n", serial_no.c_str());         }         {             std::string serial_no;             get_disk_serial_by_way_3(disk_name, serial_no);             printf("get_serial_by_way_3:[%s]\n", serial_no.c_str());         }     }     {         std::string serial_no;         get_disk_serial_by_way_4(serial_no);         printf("get_serial_by_way_4:[%s]\n", serial_no.c_str());     } }  int main(int argc, char * argv[]) {     printf("---------------\n");     test_1();     printf("---------------\n");     test_2();     printf("---------------\n");     return(0); }   已经测试：  双系统测试正常，四种方式都可以  虚拟机测试，四种方式都没有效果  U盘中系统测试， 不知道为什么/etc/mtab中查不到/dev/sda这个设备？而U盘中是有这个的 如果将设备名写死为"/dev/sda"，前三种方法才可以，很奇怪。。。

user: user-0
content: 担心，可能代码不是各自操作系统都可以，决定结合多种方案来做 1. 用13L的前半部分代码来获取设备名，失败则跳到4 2. 用13L后半部分代码获取硬盘序列号，如果获取失败，继续尝试3 3. 根据1中的设备名，按c.cpp的实现来获取设备名，失败则继续尝试4 4. 使用system，执行命令"sudo hdparm -i /dev/sda | grep SerialNo > abc.txt"，失败则尝试5 5. 使用system，执行命令"sudo lshw -class disk | grep serial > bcd.txt"，失败则放弃  先4后5是因为，5的命令执行时间比4要长太多  明天写好代码，发上来，再结帖

user: user-0
content: 回来用自己的机器测了一下， b.cpp如果将设备名改为/dev/sda是可以的 （不知道为什么下午用别人的机器不行，难道我我弄错了？） c.cpp不能改代码，改回if (sense)就可以了 （看不懂代码） 误导大家了，十分抱歉！  另外， http://blog.csdn.net/eroswang/article/details/4725121 的方法更加灵活，可以获取到设备名   #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/hdreg.h>  static int getdiskid (char *id, size_t max) {     int fd;     struct hd_driveid hid;     FILE *fp;     char line[0x100], *disk, *root, *p;      fp = fopen ("/etc/mtab", "r");     if (fp == NULL)     {         fprintf (stderr, "No /etc/mtab file.\n");         return -1;     }      fd = -1;     while (fgets (line, sizeof line, fp) != NULL)     {         disk = strtok (line, " ");         if (disk == NULL) 	{ 	    continue; 	}          root = strtok (NULL, " ");         if (root == NULL) 	{ 	    continue; 	}          if (strcmp (root, "/") == 0) 	{ 	    for (p = disk + strlen (disk) - 1; isdigit (*p); p --)             {                 *p = '\0';             } 	    fd = open (disk, O_RDONLY); 	    break; 	}     }      fclose (fp);      if (fd < 0)     {         fprintf (stderr, "open hard disk device failed.\n");         return -1;     }      if (ioctl (fd, HDIO_GET_IDENTITY, &hid) < 0)     {         fprintf (stderr, "ioctl error.\n");         return -1;     }      close (fd);      snprintf (id, max, "%s", hid.serial_no);     fprintf (stdout, "get hard disk serial number: %s\n", id);     return 0; }  int main() {     char dsk_id[256];     getdiskid(dsk_id, sizeof(dsk_id));     return(0); }

user: user-4
content: 引用 11 楼 ken_scott 的回复:[quote=引用 10 楼 dyw 的回复:] 试试这些命令： http://www.linuxjournal.com/content/tech-tip-retrieve-disk-info-command-line 然后尝试找其源代码。或者直接解析其输出结果。 谢谢，回家用正常的机器试试  如果没代码，那就解析system的结果了[/quote]  这个比较靠普

user: user-0
content: 引用 10 楼 dyw 的回复:试试这些命令： http://www.linuxjournal.com/content/tech-tip-retrieve-disk-info-command-line 然后尝试找其源代码。或者直接解析其输出结果。 谢谢，回家用正常的机器试试  如果没代码，那就解析system的结果了

user: user-5
content: 试试这些命令： http://www.linuxjournal.com/content/tech-tip-retrieve-disk-info-command-line 然后尝试找其源代码。或者直接解析其输出结果。

user: user-0
content: 敲命令吧， http://wiki.ubuntu.org.cn/UbuntuSkills#.E6.9F.A5.E7.9C.8BCPU.E4.BF.A1.E6.81.AF  #CPU ID sudo dmidecode -t 4 | grep ID #Serial Number sudo dmidecode  | grep  Serial #CPU sudo dmidecode -t 4 #BIOS sudo dmidecode -t 0 #主板： sudo dmidecode -t 2 #OEM: sudo dmidecode -t 11

user: user-0
content: 引用 6 楼 max_min_ 的回复:时间没有浪费的！至少你懂了些东西！写了代码！并测试了你的代码！ 我下午也是什么也没搞成！版本不同，导致重头再来了！ 握个爪

user: user-0
content: 引用 5 楼 q745401990 的回复:嗯嗯 花的代价太大了 就没有必要了 可以和boss 好好沟通下，把中间的缘由好好讲讲，应该没什么问题了 技术上级也是提倡用加密工具的，但BOSS坚持要自己弄一个

user: user-6
content: 时间没有浪费的！至少你懂了些东西！写了代码！并测试了你的代码！ 我下午也是什么也没搞成！版本不同，导致重头再来了！

user: user-7
content: 嗯嗯 花的代价太大了 就没有必要了 可以和boss 好好沟通下，把中间的缘由好好讲讲，应该没什么问题了

user: user-0
content: 引用 3 楼 u011779875 的回复:[quote=引用 2 楼 ken_scott 的回复:] [quote=引用 1 楼 zhao4zhong1 的回复:] 奉劝楼主不要把有限的生命浪费在无限的加密解密死循环中！ 老板舍不得花钱，怎么办。。。[/quote] 破解成本 大于购买成本时 就不要干了 这个就得权衡利弊了 还有的赚[/quote] 不是破解，目前类似于加密这边用

user: user-8
content: 引用 2 楼 ken_scott 的回复:[quote=引用 1 楼 zhao4zhong1 的回复:] 奉劝楼主不要把有限的生命浪费在无限的加密解密死循环中！ 老板舍不得花钱，怎么办。。。[/quote] 破解成本 大于购买成本时 就不要干了 这个就得权衡利弊了 还有的赚

user: user-0
content: 引用 1 楼 zhao4zhong1 的回复:奉劝楼主不要把有限的生命浪费在无限的加密解密死循环中！ 老板舍不得花钱，怎么办。。。

user: user-9
content: 奉劝楼主不要把有限的生命浪费在无限的加密解密死循环中！