获取硬盘的smart信息

Posted ziqiu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了获取硬盘的smart信息相关的知识,希望对你有一定的参考价值。

       SMART 数据储存于 WMI 中 ROOTWMIMSStorageDriver_ATASmartData 命名空间中,其中属性 ‘VendorSpecific‘ 包含有硬盘温度的数据,这是ATA标准定义的。这是一个结构大小为512字节,第一个和第二个字节代表 SMART 版本信息,从第三个字节起定义 SMART 的属性,每个属性为12字节长,每个属性的第一字节为当前属性定义,0x09 定义已经使用的小时数, 0xc2 为温度属性,第五字节表示当前温度。

技术图片

 

       本人尚处学习阶段,如有不足或错误之处,欢迎指出。

 

头文件:
#include <stdio.h> #include <windows.h> #include <WinIoCtl.h> #include <stdlib.h> #include <string.h> #include <tchar.h> #define MAX_ATTRIBUTE 30 bool Getsmart(int driver); void capacity(char* model_buf, char* sn_buf, char* fw_buf); void GetDisksmart(WORD count,DWORD driver, CHAR *modelNumber, CHAR *sn_buf, CHAR * fw_buf ); void ChangeByteOrder(PCHAR szString, USHORT uscStrSize); #pragma pack (1) typedef struct ATA_IDENTIFY_DEVICE { WORD GeneralConfiguration; //0 WORD LogicalCylinders; //1 Obsolete WORD SpecificConfiguration; //2 WORD LogicalHeads; //3 Obsolete WORD Retired1[2]; //4-5 WORD LogicalSectors; //6 Obsolete DWORD ReservedForCompactFlash; //7-8 WORD Retired2; //9 CHAR SerialNumber[20]; //10-19 WORD Retired3; //20 WORD BufferSize; //21 Obsolete WORD Obsolute4; //22 CHAR FirmwareRev[8]; //23-26 CHAR Model[40]; //27-46 WORD MaxNumPerInterupt; //47 WORD Reserved1; //48 WORD Capabilities1; //49 WORD Capabilities2; //50 DWORD Obsolute5; //51-52 WORD Field88and7064; //53 WORD Obsolute6[5]; //54-58 WORD MultSectorStuff; //59 DWORD TotalAddressableSectors; //60-61 WORD Obsolute7; //62 WORD MultiWordDma; //63 WORD PioMode; //64 WORD MinMultiwordDmaCycleTime; //65 WORD RecommendedMultiwordDmaCycleTime; //66 WORD MinPioCycleTimewoFlowCtrl; //67 WORD MinPioCycleTimeWithFlowCtrl; //68 WORD Reserved2[6]; //69-74 WORD QueueDepth; //75 WORD SerialAtaCapabilities; //76 WORD SerialAtaAdditionalCapabilities; //77 WORD SerialAtaFeaturesSupported; //78 WORD SerialAtaFeaturesEnabled; //79 WORD MajorVersion; //80 WORD MinorVersion; //81 WORD CommandSetSupported1; //82 WORD CommandSetSupported2; //83 WORD CommandSetSupported3; //84 WORD CommandSetEnabled1; //85 WORD CommandSetEnabled2; //86 WORD CommandSetDefault; //87 WORD UltraDmaMode; //88 WORD TimeReqForSecurityErase; //89 WORD TimeReqForEnhancedSecure; //90 WORD CurrentPowerManagement; //91 WORD MasterPasswordRevision; //92 WORD HardwareResetResult; //93 WORD AcoustricManagement; //94 WORD StreamMinRequestSize; //95 WORD StreamingTimeDma; //96 WORD StreamingAccessLatency; //97 DWORD StreamingPerformance; //98-99 ULONGLONG MaxUserLba; //100-103 WORD StremingTimePio; //104 WORD Reserved3; //105 WORD SectorSize; //106 WORD InterSeekDelay; //107 WORD IeeeOui; //108 WORD UniqueId3; //109 WORD UniqueId2; //110 WORD UniqueId1; //111 WORD Reserved4[4]; //112-115 WORD Reserved5; //116 DWORD WordsPerLogicalSector; //117-118 WORD Reserved6[8]; //119-126 WORD RemovableMediaStatus; //127 WORD SecurityStatus; //128 WORD VendorSpecific[31]; //129-159 WORD CfaPowerMode1; //160 WORD ReservedForCompactFlashAssociation[7]; //161-167 WORD DeviceNominalFormFactor; //168 WORD DataSetManagement; //169 WORD AdditionalProductIdentifier[4]; //170-173 WORD Reserved7[2]; //174-175 CHAR CurrentMediaSerialNo[60]; //176-205 WORD SctCommandTransport; //206 WORD ReservedForCeAta1[2]; //207-208 WORD AlignmentOfLogicalBlocks; //209 DWORD WriteReadVerifySectorCountMode3; //210-211 DWORD WriteReadVerifySectorCountMode2; //212-213 WORD NvCacheCapabilities; //214 DWORD NvCacheSizeLogicalBlocks; //215-216 WORD NominalMediaRotationRate; //217 WORD Reserved8; //218 WORD NvCacheOptions1; //219 WORD NvCacheOptions2; //220 WORD Reserved9; //221 WORD TransportMajorVersionNumber; //222 WORD TransportMinorVersionNumber; //223 WORD ReservedForCeAta2[10]; //224-233 WORD MinimumBlocksPerDownloadMicrocode; //234 WORD MaximumBlocksPerDownloadMicrocode; //235 WORD Reserved10[19]; //236-254 WORD IntegrityWord; //255 }ATA_IDENTIFY_DEVICE ; typedef struct NVME_IDENTIFY_DEVICE { CHAR Reserved1[4]; CHAR SerialNumber[20]; CHAR Model[40]; CHAR FirmwareRev[8]; CHAR Reserved2[9]; CHAR MinorVersion; SHORT MajorVersion; CHAR Reserved3[428]; }NVME_IDENTIFY_DEVICE; union IDENTIFY_DEVICE { ATA_IDENTIFY_DEVICE A; NVME_IDENTIFY_DEVICE N; }; typedef struct _SMART_ATTRIBUTE //smart属性 { BYTE Id; WORD StatusFlags; BYTE CurrentValue; BYTE WorstValue; BYTE RawValue[6]; BYTE Reserved; } SMART_ATTRIBUTE; typedef struct ATA_SMART_INFO { IDENTIFY_DEVICE identifydevice; SMART_ATTRIBUTE Attribute[MAX_ATTRIBUTE]; BYTE SmartReadData[512]; }ATA_SMART_INFO; #pragma pack ()

#include "h.h"
void capacity(char* model_buf, char* sn_buf, char* fw_buf)
{
    WORD count = 0;
    DWORD dw ;
    DWORD dwSize = MAX_PATH;
    DWORD driver = 0; 
    char szLogicalDrives[MAX_PATH] = {0}; //缓冲区
    DWORD dwResult = GetLogicalDriveStrings(dwSize,szLogicalDrives);  //获取逻辑驱动器号字符串
    //获取驱动器数
    dw = GetLogicalDrives();
    while( dw != 0 )
    {
      if((dw&1) != 0)
      {
        count++;
      }
     dw>>=1;
    }
    printf("驱动器个数:%d
",count);
    printf("------------------------------
");
    //处理获取到的结果
    if (dwResult > 0 && dwResult <= MAX_PATH) {
        char* szSingleDrive = szLogicalDrives;  //从缓冲区起始地址开始
        while(*szSingleDrive) {
            printf("Drive: %s  ", szSingleDrive);   //输出单个驱动器的驱动器号
            printf("
");

            GetDisksmart(count,driver, model_buf, sn_buf, fw_buf);
            Getsmart(driver);
             driver++;
         
            // 获取下一个驱动器号起始地址
            szSingleDrive += strlen(szSingleDrive) + 1;
        }
    }

}
#include "h.h"

const WORD IDE_ATAPI_IDENTIFY = 0xA1;   // 读取ATAPI设备的命令
const WORD IDE_ATA_IDENTIFY   = 0xEC;   // 读取ATA设备的命令
const int DISK_PATH_LEN = 128;
const int DISK_INFO_BUF_LEN = 128;

void ChangeByteOrder(PCHAR szString, USHORT uscStrSize)
{
    USHORT i;
    CHAR temp;
 
    for (i = 0; i < uscStrSize; i+=2)
    {
        temp = szString[i];
        szString[i] = szString[i+1];
        szString[i+1] = temp;
    }
}
 
 
void GetDisksmart(WORD count,DWORD driver, CHAR *modelNumber, CHAR *sn_buf, CHAR * fw_buf )
{
   // CHAR sFilePath[DISK_PATH_LEN] ;
    BOOL result;                 // results flag
    DWORD readed;                   // discard results
    HANDLE hDevice;

    char sFilePath[255] ;
    
    while(driver!=count){      //循环
    sprintf(sFilePath, "\\\\.\\PhysicalDrive%d", driver);
    
    hDevice = CreateFile(
                    sFilePath, // drive to open
                    GENERIC_READ | GENERIC_WRITE,//  GENERIC_READ|GENERIC_WRITE ,     // access to the drive
                    FILE_SHARE_READ| FILE_SHARE_WRITE , //share mode
                    NULL,             // default security attributes
                    OPEN_EXISTING,    // disposition
                    0,                // file attributes
                    NULL            // do not copy file attribute
                    );
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        printf("无法识别序列号等信息");
        //printf("------------------------------
");
        break;
        //fprintf(stderr, "CreateFile() Error: %ld
", GetLastError());
       // return (DWORD)-1;
    }

 
    GETVERSIONINPARAMS gvopVersionParams;
    
    result = DeviceIoControl(
                                   hDevice,  
                                   SMART_GET_VERSION,   //控制码
                                   NULL,
                                   0,
                                   &gvopVersionParams,   // 输出数据缓冲区指针
                                   sizeof(gvopVersionParams),   // 输出数据缓冲区指针长度
                                   &readed,                    // 输出数据实际长度单元长度
                                   NULL);
    if (!result)        //fail
    {
        printf("无法识别序列号等信息
");
        //printf("------------------------------
");
        
        break;
       // fprintf(stderr, "SMART_GET_VERSION Error: %ld
", GetLastError());
       // (void)CloseHandle(hDevice);
       // return (DWORD)-1;
    }
 
    if(0 == gvopVersionParams.bIDEDeviceMap)
    {
        printf("无法识别序列号等信息
");
        //printf("------------------------------
");
        
        break;
        //return (DWORD)-1;
    }
 
    // IDE or ATAPI IDENTIFY cmd
    BYTE btIDCmd;
    SENDCMDINPARAMS inParams;    // IDE设备IOCTL输入数据结构
    BYTE nDrive =0;
    btIDCmd = (gvopVersionParams.bIDEDeviceMap >> nDrive & 0x10) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;  
 
    // 输出 structure 
    BYTE outParams[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];   // + 512 - 1
 
    //fill in the input buffer
    inParams.cBufferSize = 0;        // 缓冲区字节数   //or IDENTIFY_BUFFER_SIZE ?
    inParams.irDriveRegs.bFeaturesReg = READ_ATTRIBUTES;     // irDriveRegs :IDE寄存器组  
    inParams.irDriveRegs.bSectorCountReg = 1;
    inParams.irDriveRegs.bSectorNumberReg = 1;
    inParams.irDriveRegs.bCylLowReg = 0;
    inParams.irDriveRegs.bCylHighReg = 0;
 
    inParams.irDriveRegs.bDriveHeadReg = (nDrive & 1) ? 0xB0 : 0xA0;
    inParams.irDriveRegs.bCommandReg = btIDCmd;
    //inParams.bDriveNumber = nDrive;
 
    //get the attributes
    result = DeviceIoControl(
                    hDevice,
                    SMART_RCV_DRIVE_DATA,
                    &inParams,
                    sizeof(SENDCMDINPARAMS) - 1,
                    outParams,
                    sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
                    &readed,
                    NULL);
    if (!result)        //获取失败
    {
        printf("无法识别序列号等信息
");
        break;
       //fprintf(stderr, "SMART_RCV_DRIVE_DATA Error: %ld
", GetLastError());
       //(void)CloseHandle(hDevice);
      // return (DWORD)-1;
    }
 
    (void)CloseHandle(hDevice);
 
    ATA_IDENTIFY_DEVICE * ip  = (ATA_IDENTIFY_DEVICE *)((SENDCMDOUTPARAMS*)outParams)->bBuffer ;  //ip指向获取的硬盘信息
  
    // 固件
    memset(fw_buf, 0, 8);
    memcpy(fw_buf, ip->FirmwareRev, 8);
    fw_buf[8] = ;
    ChangeByteOrder(fw_buf, 8);
    printf("
->固  件: %s", fw_buf);
 
    // 型号
    memset(modelNumber, 0, 40);
    memcpy(modelNumber, ip->Model, 40);
    modelNumber[40] = ;
    ChangeByteOrder(modelNumber, 40);
    printf("
->型  号: %s", modelNumber);
    
      // 序列号
    memset(sn_buf, 0, 20);
    memcpy(sn_buf, ip->SerialNumber+12, 12);
    sn_buf[12] = ;
    ChangeByteOrder(sn_buf,20);
    printf("
->序列号: %s
", sn_buf);
 
    
   

 //  printf("------------------------------
");
   
    break;
    }  

 
//    return 0;
}


#include "h.h"

bool Getsmart(int driver)
{
// CHAR sFilePath[DISK_PATH_LEN] ;
BOOL result; //DeviceIoControl返回值
DWORD readed;
HANDLE hDevice; //文件句柄


char sFilePath[255];
sprintf(sFilePath, "\\\\.\\PhysicalDrive%d", driver);
hDevice = CreateFile(
sFilePath, // drive to open
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ| FILE_SHARE_WRITE ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE)
{

fprintf(stderr, "CreateFile() Error: %ld ", GetLastError());
return false;
}



// 输出 structure
STORAGE_PREDICT_FAILURE spf = {0};


result = DeviceIoControl(
hDevice,
IOCTL_STORAGE_PREDICT_FAILURE, //控制码
&spf,
sizeof(spf) ,
&spf,
sizeof(spf) ,
&readed,
NULL);
if (!result) //fail
{

fprintf(stderr, "SMART_RCV_DRIVE_DATA Error: %ld ", GetLastError());
(void)CloseHandle(hDevice);
printf("------------------------------ ");
return false;
}

(void)CloseHandle(hDevice);
ATA_SMART_INFO asi;
memcpy_s(&(asi.SmartReadData), 512, &(spf.VendorSpecific), 512);


int j = 0;
for(int i = 0; i < MAX_ATTRIBUTE; i++)
{
char buf[sizeof(WORD)+1];
int sum=0,y=1,count=1, x=0;
//DWORD rawValue = 0;


memcpy( &(asi.Attribute[j]),
&(asi.SmartReadData[i * sizeof(SMART_ATTRIBUTE) + 2]), sizeof(SMART_ATTRIBUTE));


if(asi.Attribute[j].Id != 0)
{
switch(asi.Attribute[j].Id)
{
case 0x09: // Power on Hours

printf(" ID: 09 通电时间 : ");

for(int k =0;k<=6;k++){
itoa((int)asi.Attribute[j].RawValue[k],buf,16); //转换为十六进制

for(x=sizeof(WORD)-1;x>=0;x--){

if(buf[x]!=0)
switch(buf[x])
{
case ‘a‘:
sum=sum+10*y; y*=16; break;
case ‘b‘:
sum=sum+11*y; y*=16; break;
case ‘c‘:
sum=sum+12*y; y*=16;break;
case ‘d‘:
sum=sum+13*y; y*=16; break;
case ‘e‘:
sum=sum+14*y; y*=16;break;
case ‘f‘:
sum=sum+15*y; y*=16; break;
default :
sum=sum+((int)buf[x]-48)*y; y*=16;break; //不能转化为WORD,而要使用int
};

}
}
printf("%d 小时 ",sum);
sum=0;y=1;x=0;
break;


case 0x0C: // Power On Count

printf("ID: 0c 通电次数 : ");
for(int k =0;k<=6;k++){


itoa((WORD)asi.Attribute[j].RawValue[k],buf,16); //转换为十六进制


for(x=sizeof(WORD)-1;x>=0;x--){

if(buf[x]!=0)
switch(buf[x])
{
case ‘a‘:
sum=sum+10*y; y*=16; break;
case ‘b‘:
sum=sum+11*y; y*=16; break;
case ‘c‘:
sum=sum+12*y; y*=16;break;
case ‘d‘:
sum=sum+13*y; y*=16; break;
case ‘e‘:
sum=sum+14*y; y*=16;break;
case ‘f‘:
sum=sum+15*y; y*=16; break;
default :
sum=sum+((int)buf[x]-48)*y; y*=16;break;
};

}
}
printf("%d 小时 ",sum);
sum=0;y=1;x=0;
break;

case 0xC2: // Temperature
printf("ID: c2 温 度 : ");
printf("%d ℃ ",(WORD)asi.Attribute[j].RawValue[0]);
break;

default:
break;
}
j++;
}
}
printf("------------------------------ ");
return true;
}


#include "h.h"

int main()
{
  char model_buf[40+1], sn_buf[20+1], fw_buf[8+1];
  capacity( model_buf, sn_buf, fw_buf);
 // Getsmart();
  getchar();
  return 0;
}

 

以上是关于获取硬盘的smart信息的主要内容,如果未能解决你的问题,请参考以下文章

固态硬盘不支持smart

使用 PowerShell 通过电子邮件通知获取硬盘 SMART 数据

硬盘出现SMART检测失败是啥情况

ESXi主机 查看硬盘健康信息(SMART)

运行硬盘Smart检测无法通过能说明啥??

linux如何读取u盘smart信息