Linux下获取CPUID、硬盘序列号与 MAC地址
Linux下获取CPUID、硬盘序列号与 MAC地址
在很多系统软件的开发中,需要使用一些系统的唯一性 信息。所以,得到主机的CPUID、硬盘序列号及网卡的MAC地址,就成个一件很重要的应用。
本人经过一番google即自己的钻研,基本上实现了这几个功能。需要的准备知识有:
1.GCC的嵌入汇编,具体的GCC嵌入汇编知识,请参考相关手册
2.ioctl系统调用,具体的调用方法,请查看手册页
获取CPUID
按照网上提供的说明,CPUID并不是所有的Intel CPU都支持的。如果支持,汇编调用为:eax置0000_0003,调用cpuid。
以下为实现代码(在我的CPU上,并没有得到):
#define cpuid(in,a,b,c,d)  asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
static int
getcpuid (char *id, size_t max)
{
  int i;
  unsigned long li, maxi, maxei, ebx, ecx, edx, unused;
  cpuid (0, maxi, unused, unused, unused);
  maxi &= 0xffff;
  if (maxi < 3)
    {
      return -1;
    }
  cpuid (3, eax, ebx, ecx, edx);
  snprintf (id, max, "%08lx %08lx %08lx %08lx", eax, ebx, ecx, edx);
  fprintf (stdout, "get cpu id: %s\n", id);
  return 0;
}
获取硬盘序列号
这个的实现,采用的是读取/etc/mtab文件,到/(即根目录)挂载的设备文件,然后打开它,再用系统调用 ioctl来实现的。
ioctl第二个参数为HDIO_GET_IDENTITY, 获得指定文件描述符的标志号
ioctl的第三个参数为struct hd_driveid *,在linux/hdreg.h中,struct hd_driveid的声明有
struct hd_driveid {
        unsigned short  config;        /* lots of obsolete bit flags */
        unsigned short  cyls;          /* Obsolete, "physical" cyls */
        unsigned short  reserved2;      /* reserved (word 2) */
        unsigned short  heads;          /* Obsolete, "physical" heads */
        unsigned short  track_bytes;    /* unformatted bytes per track */
        unsigned short  sector_bytes;  /* unformatted bytes per sector */
        unsigned short  sectors;        /* Obsolete, "physical" sectors per track */
        unsigned short  vendor0;        /* vendor unique */
        unsigned short  vendor1;        /* vendor unique */
        unsigned short  vendor2;        /* Retired vendor unique */
        unsigned char  serial_no[20];  /* 0 = not_specified */
        unsigned short  buf_type;      /* Retired */
        unsigned short  buf_size;      /* Retired, 512 byte increments
                                        * 0 = not_specified
                                        */
        ……
};
, 这其中,serial_no为硬盘的序列号。如果此项为0,则为没有提供。
思路明确了,以下为实现代码:
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;
}
获取MAC地址
通过创建一个socket,然后bind特定的IP地址,就可以通过ioctl得到这个套按地绑定的网络接口名称。然 后再通过网络接口名称,得到MAC地址。
如果ioctl的第二个参数为SIOCGIFNAME, 则获得指定网络接口的名称;如果ioctl的第二个参数为SIOCGIFHWADDR,则获得指定网络接口的MAC地址
ioctl的第三个参数为struct ifreq *,在linux/if.h头文件里,struct ifreq声明如下:
struct ifreq
{
#define IFHWADDRLEN    6
        union
        {
                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
        } ifr_ifrn;
        union {
                struct  sockaddr ifru_addr;
                struct  sockaddr ifru_dstaddr;
                struct  sockaddr ifru_broadaddr;
                struct  sockaddr ifru_netmask;
                struct  sockaddr ifru_hwaddr;
                short  ifru_flags;
                int    ifru_ivalue;
                int    ifru_mtu;
                struct  ifmap ifru_map;
                char    ifru_slave[IFNAMSIZ];  /* Just fits the size */
                char    ifru_newname[IFNAMSIZ];
                void *  ifru_data;
                struct  if_settings ifru_settings;
        } ifr_ifru;
}
, 其中,ifrn_name为网络接口的名称,ifr_ifru.ifru_hwaddr为网络接口的MAC地址。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。