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


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

需要的准备知识有:

  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,则为没有提供。

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

#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;
}

获取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地址。
#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 进程信息伪装文件系统

你可能感兴趣的:(Linux基础)