11

I need to get specifications of hard disk on both Win and *nix machines. I used <hdreg.h> on Linux like this:

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

I need hd_driveid to tell me some more information about disk. I want to know:

  • Number of partitions
  • Specifications of each partition (format, label, flags, size, start point, number of tracks etc.)
  • Number of tracks per cylinder
  • Number of total tracks
  • Maximum block size
  • Minimum Block size
  • Default block size
  • Total size of device

My questions are:

  1. Is there a common (platform-independent) way to connect hardware? I would like use same code for win and *nix. (even if there was no way other than embedding assembly code into cpp)
  2. If there isn't, how do I get above information in *nix?
sorush-r
  • 10,490
  • 17
  • 89
  • 173
  • 1
    Some systems don't have partitions... Some (typically in the *BSD's) use "slices" instead, and others could well be just using the full hard drive. (ie, unpartitioned). – Arafangion Mar 04 '11 at 13:36

5 Answers5

9

Nearly everything in your list has nothing to do with "specifications of hard disk":

  • 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.

It might help if you told us why you wanted this information...

tc.
  • 33,468
  • 5
  • 78
  • 96
  • 1
    Thanks tc. I overcome by `T=t×S` where S is `sectors` and t is number of tracks. I don't know what is `block size` and I can't find it anywhere else than my teachers C# example. in this example there is an instance of `ManagementObject` and such information are extracted from it by a string indexer... (I forgot to say I'm writing a homework :-) – sorush-r Mar 04 '11 at 13:48
  • 1
    Parameters like hd.model, hd.serial_no are real. May somebody give me a tip why am I getting a hd_driveid.sector_bytes equal to zero? I need only this parameter and it's equal to zero... – Tebe Apr 11 '12 at 22:48
  • 1
    @shbk: It may be better to start a new question stating exactly what hardware you're using, the full code you ran, and what it outputs. It's also much easier to help if you explain what you are trying to ultimately achieve. – tc. Apr 16 '12 at 15:37
  • You should use `#ifndef` around defining "file offset bits" so it doesn't repeatedly define itself. – DaCuteRaccoon Oct 17 '22 at 22:25
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;
//---
Amit Vujic
  • 1,632
  • 1
  • 24
  • 32
3

No, there is no platform-independent way. There is even no *nix way. There is just Linux way.

In Linux, all relevant information is available in various files in the /proc filesystem. The /proc/devices will tell you what devices there are (the files in /dev/ may exist even when the devices are not available, though opening them will fail in that case), /proc/partitions will tell you what partitions are available on each disk and than you'll have to look in the various subdirectories for the information. Just look around on some linux system where is what you need.

Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • 1
    Thanks for your answer but I cant find what I need there... I wondered how that files in `/proc` are created? I want gain hardware info myself in my program :-) (in the same way that they are generated in `/proc`) – sorush-r Mar 04 '11 at 12:38
  • 3
    @Sorush the 'files' in proc are really a special file system (called procfs) that read and/or write directly to the kernel. You'll need to dig into the linux kernel to find out HOW procfs gets its data. The whole point of procfs was to expose data w/o needing to be a kernel hacker. – KitsuneYMG Mar 04 '11 at 12:54
  • 1
    @Sorush: You will have to dig around quite a bit to collect all you need. Unfortunately I am not on a Linux system now and I don't remember the precise files, but there is something like `/proc/bus/ide` and `/proc/bus/scsi` and some other and there are many files with various bits of information which you'll need to collect. – Jan Hudec Mar 07 '11 at 13:54
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 );
//---
Amit Vujic
  • 1,632
  • 1
  • 24
  • 32
2

For GNU/Linux have a look at this: obtaining hard disk metadata

fpmurphy
  • 2,464
  • 1
  • 18
  • 22