如何使用C++在Linux中获取硬件信息

11

我需要获取Win和*nix机器上硬盘的规格。在Linux上,我使用了如下的<hdreg.h>

   static struct hd_driveid hd;
   int device;
   if ((device = open("/dev/sda", O_RDONLY | O_NONBLOCK)) < 0)
   {
      cerr << "ERROR: Cannot open device /dev/sda \n";
      exit(1);
   }

   if (!ioctl(device, HDIO_GET_IDENTITY, &hd))
   {
      cout << hd.model << endl;
      cout << hd.serial_no << endl;
      cout << hd.heads << endl;
   }

我需要hd_driveid来提供更多有关磁盘的信息。我想知道:

  • 分区数量
  • 每个分区的规格(格式、标签、标志、大小、起始点、轨道数等)
  • 每个柱面的轨道数
  • 总轨道数
  • 最大块大小
  • 最小块大小
  • 默认块大小
  • 设备的总大小

我的问题是:

  1. 是否有一种通用的(与平台无关的)方式来连接硬件?我希望在win和*nix上使用相同的代码。(即使没有其他方法,除了将汇编代码嵌入到cpp中)
  2. 如果没有,如何在*nix中获取上述信息?

1
有些系统没有分区……一些系统(通常是在*BSD中)使用“切片”代替,而其他系统可能只是使用整个硬盘(即未分区)。 - Arafangion
5个回答

9
几乎你列表中的所有内容都与“硬盘规格”无关:
  • The number of partitions depends on reading the partition table, and if you have any extended partitions, the partition tables of those partitions. The OS will usually do this bit for you when the device driver loads.
  • Partition information (namely the volume label) typically isn't available in the partition table. You need to guess the file system type and parse the file system header. The only thing in the partition table is the "type" byte, which doesn't tell you all that much, and the start/size.
  • Hard drives won't give you "real" CHS information. Additionally, the CHS information that the drive provides is "wrong" from the point of view of the BIOS (the BIOS does its own fudging).
  • Hard drives have a fixed sector size, which you can get with hd_driveid.sector_bytes (usually 512, but some modern drives use 4096). I'm not aware of a maximum "block size", which is a property of the filesystem. I'm also not sure why this is useful.
  • The total size in sectors is in hd_driveid.lba_capacity_2. Additionally, the size in bytes can probably be obtained with something like

    #define _FILE_OFFSET_BITS 64
    #include <sys/types.h>
    #include <unistd.h>
    
    ...
    off_t size_in_bytes = lseek(device, 0, SEEK_END);
    if (size_in_bytes == (off_t)-1) { ... error, error code in ERRNO ... }
    

    Note that in both cases, it'll probably be a few megabytes bigger than sizes calculated by C×H×S.

如果您告诉我们需要此信息的原因,可能会有所帮助...


1
谢谢tc。我通过 T=t×S 克服了问题,其中 S 是“扇区”,t 是磁道数。我不知道什么是“块大小”,除了我的老师的 C# 示例之外,我找不到其他任何信息。在这个示例中,有一个 ManagementObject 实例,并且这些信息是通过字符串索引器从中提取的...(我忘了说我正在写作业 :-)) - sorush-r
1
类似 hd.model、hd.serial_no 这样的参数是真实存在的。有谁能给我一个提示,为什么 hd_driveid.sector_bytes 的值为零?我只需要这个参数,但它却等于零... - Tebe
1
@shbk:最好新开一个问题,明确说明你使用的硬件、运行的完整代码以及输出结果。如果你能解释你最终想要实现什么,那么帮助你也会更容易些。 - tc.
你应该在定义“文件偏移位”时使用#ifndef,这样它就不会重复定义自己。 - user17585064

6
//-------------------------------------------------
// Without Boost LIB usage
//-------------------------------------------------
#include <sys/statvfs.h>
#include <sys/sysinfo.h>
//-------------------------------------------------
stringstream   strStream;
unsigned long  hdd_size;
unsigned long  hdd_free;
ostringstream  strConvert;
//---
struct sysinfo info;
sysinfo( &info );   
//---
struct statvfs fsinfo;
statvfs("/", &fsinfo);
//---
//---
unsigned num_cpu = std::thread::hardware_concurrency();
//---
ifstream cpu_freq("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq");
strStream << cpu_freq.rdbuf();
std::string  cpufrequency = strStream.str();
//---
strStream.str("");
ifstream cpu_temp("/sys/class/thermal/thermal_zone0/temp");
strStream << cpu_temp.rdbuf();
strConvert<< fixed << setprecision(2) << std::stof(strStream.str());
std::string cputemp = strConvert.str();
//---
std::string   mem_size = to_string( (size_t)info.totalram *     (size_t)info.mem_unit );
//---
hdd_size = fsinfo.f_frsize * fsinfo.f_blocks;
hdd_free = fsinfo.f_bsize * fsinfo.f_bfree;  
//---                                                
std::cout << "CPU core number           ==" << num_cpu       << endl;
std::cout << "CPU core speed            ==" << cpufrequency  << endl;
std::cout << "CPU temperature (C)       ==" << cputemp       << endl;
//---
std::cout << "Memory size               ==" << mem_size      << endl;
//---
std::cout << "Disk, filesystem size     ==" << hdd_size      << endl;
std::cout << "Disk free space           ==" << hdd_free      << endl;
//---

3
不,没有跨平台的方式。即使是在*nix中,也没有通用的方式。只有Linux方法。
在Linux中,所有相关信息都可以在/proc文件系统中的各种文件中找到。 /proc/devices会告诉您有哪些设备(即使设备不可用,/dev/中的文件可能仍然存在,但在这种情况下打开它们将失败),/proc/partitions会告诉您每个磁盘上有哪些分区,然后您必须在各个子目录中查找信息。只需要在一些Linux系统上查看您需要的东西即可。

1
谢谢你的回答,但我在那里找不到我需要的东西...我想知道/proc目录下的文件是如何创建的?我想在我的程序中自己获取硬件信息 :-)(以与/proc中生成它们的方式相同) - sorush-r
3
在/proc目录下的“文件”实际上是一种特殊的文件系统(称为procfs),可以直接读取和/或写入内核。你需要深入研究Linux内核,以了解procfs如何获取其数据。整个procfs的意义在于无需成为内核开发人员即可公开数据。 - KitsuneYMG
1
@Sorush:你需要花费一些时间来收集所需的所有内容。不幸的是,我现在不在Linux系统上,也记不清确切的文件了,但是有类似于“/proc/bus/ide”和“/proc/bus/scsi”的东西,还有其他一些文件,其中包含各种信息,你需要收集它们。 - Jan Hudec

2
//Piece of code working for me with Boost LIB usage
//-----------------------------------------------------
#include <sys/sysinfo.h>
#include <boost/filesystem.hpp>
//---    
using namespace boost::filesystem;
//---
struct sysinfo info;
sysinfo( &info );
//---
space_info si = space(".");
//---
unsigned num_cpu = std::thread::hardware_concurrency();
//---
ifstream  cpu_freq("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq");
ifstream cpu_temp("/sys/class/thermal/thermal_zone0/temp");
//---
std::string cpunumber = to_string(num_cpu);
std::string cpufrequency = cpu_freq.str();
std::string cputemp = cpu_temp.str();
std::string mem_size = to_string( (size_t)info.totalram *     (size_t)info.mem_unit );
std::string disk_available = to_string(si.available);
std::string fslevel = to_string( (si.available/si.capacity)*100 );
//---

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接