在很多系统软件的开发中,需要使用一些系统的唯一性信息。所以,得到主机的CPUID、硬盘序列号及网卡的MAC地址,就成个一件很重要的应用。
需要的准备知识有:
按照网上提供的说明,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,则为没有提供。
思路明确了,以下为实现代码:
#include
#include
#include
#include
#include
#include
#include
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; }
通过创建一个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地址。
#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#include #include #include #include #include #include #include #include #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']
查看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 进程信息伪装文件系统