您的位置:首页 > 运维架构 > Linux

在LINUX下探测硬件信息的命令

2017-03-06 21:13 633 查看
在很多系统软件的开发中,需要使用一些系统的唯一性信息。所以,得到主机的CPUID、硬盘序列号及网卡的MAC地址,就成个一件很重要的应用。

需要的准备知识有:
GCC的嵌入汇编,具体的GCC嵌入汇编知识,请参考相关手册
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的声明有
<em>struct hd_driveid {
unsigned short	config;		/</em> 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,则为没有提供。

思路明确了,以下为实现代码:

#include <string.h>

#include<stdio.h>

#include <sys/ioctl.h>

#include <linux/hdreg.h>

#include <fcntl.h>

#include <stdlib.h>

#include<ctype.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;
}


获取MAC地址

通过创建一个socket,然后bind特定的IP地址,就可以通过ioctl得到这个套按地绑定的网络接口名称。然后再通过网络接口名称,得到MAC地址。

如果ioctl的第二个参数为SIOCGIFNAME, 则获得指定网络接口的名称;如果ioctl的第二个参数为SIOCGIFHWADDR,则获得指定网络接口的MAC地址

ioctl的第三个参数为struct ifreq ,在linux/if.h头文件里,struct ifreq声明如下:
<em>struct ifreq
{
#define IFHWADDRLEN	6
union
{
char	ifrn_name[IFNAMSIZ];		/</em> 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地址。
#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;
}
第二种方法:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <errno.h>

#define ETH_NAME	"eth0"

int main()
{
int sock;
struct sockaddr_in sin;
struct sockaddr sa;
struct ifreq ifr;
unsigned char mac[6];

sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
perror("socket");
return -1;
}

strncpy(ifr.ifr_name, ETH_NAME, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;

if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
{
perror("ioctl");
return -1;
}

memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
fprintf(stdout, "%s ip: %s\n", ETH_NAME, inet_ntoa(sin.sin_addr));

memset(mac, 0, sizeof(mac));
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl");
return -1;
}

memcpy(&sa, &ifr.ifr_addr, sizeof(sin));
memcpy(mac, sa.sa_data, sizeof(mac));
fprintf(stdout, "%s mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", ETH_NAME, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return 0;
}

SD卡ID获取

使用以下命令:cat /sys/devices/platform/jz-msc.0/mmc_host/mmc0/mmc0:1234/cid或者使用通配符cat /sys/devices/platform/jz-msc.0/mmc_host/mmc0/mmc0:*/cid 得到32个字节的数据:0254 4d53 4130 3847 0610 ebb5 5000 a93f 在kernel/drivers/mmc/core/sd.c文件中:以下数组结构用于保存SD卡ID card->raw_cid[0];card->raw_cid[1];card->raw_cid[2];card->raw_cid[3];
linux内核中对应的代码位于: kernel/drivers/mmc/core/sd.ckernel/drivers/mmc/core/mmc.ckernel/include/linux/mmc/card.hkernel/include/linux/mmc/mmc.h 关键字: Linux MMC卡驱动读取SD卡ID如何读取SD卡ID如何获取SD卡ID如何获取SD卡序列号

在LINUX下探测硬件信息的命令

查看服务器的机器型号和序列号: dmidecode | grep "Product"
用硬件检测程序kudzu探测新硬件:service kudzu start ( or restart)
查看CPU信息:cat /proc/cpuinfo
查看板卡信息:cat /proc/pci
查看PCI信息:lspci (相比cat /proc/pci更直观)
查看内存信息:cat /proc/meminfo
查看网卡信息 : lshw -C network 或者lshw -class network
查看网卡型号 : lspci | grep Ethernet
查看USB设备:cat /proc/bus/usb/devices
查看键盘和鼠标:cat /proc/bus/input/devices
查看系统硬盘信息和使用情况:fdisk & disk - l & df
查看各设备的中断请求(IRQ):cat /proc/interrupts
查看系统体系结构:uname -a
dmidecode查看硬件信息,包括bios、cpu、内存等信息
dmesg | more 查看硬件信息
对于“/proc”中文件可使用文件查看命令浏览其内容,文件中包含系统特定信息:
Cpuinfo 主机CPU信息
Dma 主机DMA通道信息
Filesystems 文件系统信息
Interrupts 主机中断信息
Ioprots 主机I/O端口号信息
Meninfo 主机内存信息
Version Linux内存版本信息
还有一个关于硬盘的命令:hdparm(可以用来优化硬盘,这里只是查看信息)
显示硬盘的相关设置
#hdparm /dev/sda
/dev/sda:
 HDIO_DRIVE_CMD(identify) failed: Invalid exchange
 readonly = 0 (off)
 readahead = 256 (on)
 geometry = 35539[柱面数]/255[磁头数]/63[扇区数], sectors = 570949632[总扇区数], start = 0[起始扇区数]
显示硬盘的柱面、磁头、扇区数
#hdparm -g /dev/sda
/dev/sda:
geometry = 35539[柱面数]/255[磁头数]/63[扇区数], sectors = 570949632[总扇区数], start = 0[起始扇区数]
评估硬盘的读取效率(停止所有服务,多测几次)
root@ubuntu:~# hdparm -T /dev/sda
/dev/sda:
 Timing cached reads: 7540 MB in 2.00 seconds = 3771.50 MB/sec
root@ubuntu:~# hdparm -t /dev/sda
/dev/sda:
 Timing buffered disk reads: 226 MB in 3.04 seconds = 74.36 MB/sec
root@ubuntu:~# hdparm -Tt /dev/sda
/dev/sda:
 Timing cached reads: 7750 MB in 2.00 seconds = 3876.91 MB/sec
 Timing buffered disk reads: 270 MB in 3.00 seconds = 89.99 MB/sec
-T
用于以基准测试和比较为目的的缓存读取计时.要得到有意义的结果, 应该在内存不少于2M,系统没有其它活动(没有其它活动的程序) 的条件下,重复操作2-3次.它显示了不存取磁盘直接从Linux缓存 读取数据的速度.这项测量实际上标示了被测系统的处理器,缓存 和内存的吞吐量. 如果标志 -t 也被指定,那么一个基于
-T 输出结果的修正量将被综合到 -t 操作报告的结果中.
-t
用于以基准测试和比较为目的的缓存读取计时.要得到有意义的结果, 应该在内存不少于2M,系统没有其它活动(没有其它活动的程序) 的条件下,重复操作2-3次.它显示了不使用预先的数据缓冲从磁盘 这项测量标示了Linux下没有任何文件系统开销时磁盘可以支持多快的连续数据读取.为确保测量的精确,缓存在 -t 的过程中通过BLKFLSBUF控制被刷新.
如果标志 -T 也被指定,那么一个基于 -T 数促结果的修正量将被综合到 -t 操作报告的结果中.

   系统

    # uname -a # 查看内核/操作系统/CPU信息

    # head -n 1 /etc/issue # 查看操作系统版本

    # cat /proc/cpuinfo # 查看CPU信息

    # hostname # 查看计算机名

    # lspci -tv # 列出所有PCI设备

    # lsusb -tv # 列出所有USB设备

    # lsmod # 列出加载的内核模块

    # env # 查看环境变量
   
    资源
    # free -m # 查看内存使用量和交换区使用量

    # df -h # 查看各分区使用情况

    # du -sh <目录名> # 查看指定目录的大小

    # grep MemTotal /proc/meminfo # 查看内存总量

    # grep MemFree /proc/meminfo # 查看空闲内存量

    # uptime # 查看系统运行时间、用户数、负载

    # cat /proc/loadavg # 查看系统负载
   
    磁盘和分区

    # mount | column -t # 查看挂接的分区状态

    # fdisk -l # 查看所有分区

    # swapon -s # 查看所有交换分区

    # hdparm -i /dev/hda # 查看磁盘参数(仅适用于IDE设备)

    # dmesg | grep IDE # 查看启动时IDE设备检测状况
   
    网络

    # ifconfig # 查看所有网络接口的属性

    # iptables -L # 查看防火墙设置

    # route -n # 查看路由表

    # netstat -lntp # 查看所有监听端口

    # netstat -antp # 查看所有已经建立的连接

    # netstat -s # 查看网络统计信息
   
    进程

    # ps -ef # 查看所有进程

    # top # 实时显示进程状态
   
    用户
    # w # 查看活动用户

    # id <用户名> # 查看指定用户信息

    # last # 查看用户登录日志

    # cut -d: -f1 /etc/passwd # 查看系统所有用户

    # cut -d: -f1 /etc/group # 查看系统所有组

    # crontab -l # 查看当前用户的计划任务
   
    服务

    # chkconfig --list # 列出所有系统服务
    # chkconfig --list | grep on # 列出所有启动的系统服务
   
    程序

    # rpm -qa # 查看所有安装的软件包

    常用命令整理如下:

    查看主板的序列号: dmidecode | grep -i 'serial number'

    用硬件检测程序kuduz探测新硬件:service kudzu start ( or restart)

    查看CPU信息:cat /proc/cpuinfo [dmesg | grep -i 'cpu'][dmidecode -t processor]

    查看内存信息:cat /proc/meminfo [free -m][vmstat]

    查看板卡信息:cat /proc/pci

    查看显卡/声卡信息:lspci |grep -i 'VGA'[dmesg | grep -i 'VGA']

    查看网卡信息:dmesg | grep -i 'eth'[cat /etc/sysconfig/hwconf | grep -i eth][lspci | grep -i 'eth']

    <!--more-->

    查看PCI信息:lspci (相比cat /proc/pci更直观)
    查看USB设备:cat /proc/bus/usb/devices
    查看键盘和鼠标:cat /proc/bus/input/devices

    查看系统硬盘信息和使用情况:fdisk & disk – l & df

    查看各设备的中断请求(IRQ):cat /proc/interrupts

    查看系统体系结构:uname -a

    查看及启动系统的32位或64位内核模式:isalist –v [isainfo –v][isainfo –b]

    dmidecode查看硬件信息,包括bios、cpu、内存等信息
    测定当前的显示器刷新频率:/usr/sbin/ffbconfig –rev \?

    查看系统配置:/usr/platform/sun4u/sbin/prtdiag –v

    查看当前系统中已经应用的补丁:showrev –p

    显示当前的运行级别:who –rH

    查看当前的bind版本信息:nslookup –class=chaos –q=txt version.bind

    dmesg | more 查看硬件信息

    lspci 显示外设信息, 如usb,网卡等信息

    lsnod 查看已加载的驱动
    lshw

    psrinfo -v 查看当前处理器的类型和速度(主频)

    prtconf -v 打印当前的OBP版本号

    iostat –E 查看硬盘物理信息(vendor, RPM, Capacity)

    prtvtoc /dev/rdsk/c0t0d0s 查看磁盘的几何参数和分区信息
    df –F ufs –o i 显示已经使用和未使用的i-node数目
    isalist –v
   
   
    备注: proc – process information pseudo-filesystem 进程信息伪装文件系统
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: