首页
登录 | 注册

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, eax, 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];
char ifru_newname[IFNAMSIZ];
void * ifru_data;
struct if_settings ifru_settings;
} ifr_ifru;
}

,其中,ifrn_name为网络接口的名称,ifr_ifru.ifru_hwaddr为网络接口的MAC地址。 #ifndef MAX_IFINDEX
# define MAX_IFINDEX 8
#endif

static int
getmacaddr (const char *ip, char *id, size_t max)
{

int i, sockfd;
struct sockaddr_in *loc;
struct ifreq req[1];

sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
fprintf (stderr, "Unable to create socket./n");
return -1;
}

for (i = 0; i <= MAX_IFINDEX; ++ i)
{
req->ifr_ifindex = i;

if (ioctl (sockfd, SIOCGIFNAME, req) < 0)
{
fprintf (stderr, "ioctl error: %s/n", strerror (errno));
continue;
}

if (ioctl (sockfd, SIOCGIFADDR, req) < 0)
{
fprintf (stderr, "ioctl interface index [%d] error: %s/n", i, strerror (errno));
continue;
}

loc = (struct sockaddr_in *) (&(req->ifr_ifru.ifru_addr));
if (loc->sin_addr.s_addr == inet_addr (ip))
{
fprintf (stderr, "%s bind at %s./n", ip, req->ifr_name);
break;
}
}

if (i > MAX_IFINDEX)
{
fprintf (stderr, "input IP error./n");
close (sockfd);
return -1;
}

if (ioctl (sockfd, SIOCGIFHWADDR, req) < 0)
{
fprintf (stderr, "ioctl error: %s/n", strerror (errno));
close (sockfd);
return -1;
}

close (sockfd);

snprintf (id, max, "%02X%02X%02X%02X%02X%02X",
req->ifr_hwaddr.sa_data[0] & 0xff,
req->ifr_hwaddr.sa_data[1] & 0xff,
req->ifr_hwaddr.sa_data[2] & 0xff,
req->ifr_hwaddr.sa_data[3] & 0xff,
req->ifr_hwaddr.sa_data[4] & 0xff,
req->ifr_hwaddr.sa_data[5] & 0xff);

fprintf (stdout, "MAC address of %s: [%s]./n", req->ifr_name, id);
return 0;
}
转载地址:http://blog.csdn.net/eroswang/article/details/4725121

相关文章

  •     最近经常使用svn进行代码管理,这些命令老是记不住,得经常上网查,终于找了一个linux下svn命令使用大全:1.将文件checkout到本地目录 svn checkout path(path是服务器 上的目录)例如:svn che ...
  • Subversion是一个自由,开源的版本控制系统.在Subversion管理下,文件和目录可以超越时空,下面我们就一起来看看在Linux下yum apt-get安装subversion 1.8的方法吧. 一直想找一个源可以使用 yum 或 ...
  • 该博文主要介绍了Linux下:安装db2v9.7.安装db2补丁.创建实例.db2数据库实例参数调整.dbm参数配置优化以及db2全局变量的设置和db2数据库的基本日常操作等相关内容! 一.Linux下安装db2 V9.7 1.解压缩gz包 ...
  • Linux下Redis的安装和部署
    Redis是当前比较热门的NOSQL系统之一,它是一个key-value存储系统.和Memcache类似,但很大程度补偿了Memcache的不足,它支持存储的value类型相对更多,包括string.list.set.zset和hash.这 ...
  • 最近在做一个项目,是在debian的linux环境下用java开发的,因为系统没有安装图形界面,于是采用调用浏览器显示特定网页来实现的方案.       现在可以找到的java调用linux浏览器的方法主要有3种,       第一种是调用 ...
  • Code: #include #include #include #include #include #include #include #include #define I2C_DEV "/dev/i2c-1" #de ...

2020 unjeep.com webmaster#unjeep.com
12 q. 0.015 s.
京ICP备10005923号