236 lines
5.6 KiB
C++
236 lines
5.6 KiB
C++
/**
|
|
* @file smart.cpp
|
|
* @brief read S.M.A.R.T values
|
|
* @author hendrik schutter
|
|
* @date 01.05.2020
|
|
*/
|
|
|
|
#include "../include/reHDD.h"
|
|
|
|
string SMART::modelFamily;
|
|
string SMART::modelName;
|
|
string SMART::serial;
|
|
uint64_t SMART::capacity = 0U;
|
|
uint32_t SMART::errorCount = 0U;
|
|
uint32_t SMART::powerOnHours = 0U;
|
|
uint32_t SMART::powerCycle = 0U;
|
|
uint32_t SMART::temperature = 0U;
|
|
|
|
/**
|
|
* \brief get and set S.M.A.R.T. values in Drive
|
|
* \param pointer of Drive instance
|
|
* \return void
|
|
*/
|
|
void SMART::readSMARTData(Drive *drive)
|
|
{
|
|
modelFamily.clear();
|
|
modelName.clear();
|
|
serial.clear();
|
|
capacity = 0U;
|
|
errorCount = 0U;
|
|
powerOnHours = 0U;
|
|
powerCycle = 0U;
|
|
temperature = 0U;
|
|
|
|
string sSmartctlCommands[] = {" --json -a ", " --json -d sntjmicron -a ", " --json -d sntasmedia -a ", " --json -d sntrealtek -a "};
|
|
|
|
for (string sSmartctlCommand : sSmartctlCommands)
|
|
{
|
|
string sCMD = ("smartctl");
|
|
sCMD.append(sSmartctlCommand);
|
|
sCMD.append(drive->getPath());
|
|
const char *cpComand = sCMD.c_str();
|
|
|
|
FILE *outputfileSmart = popen(cpComand, "r");
|
|
size_t len = 0; // length of found line
|
|
char *cLine = NULL; // found line
|
|
uint8_t status = 255;
|
|
|
|
while ((getline(&cLine, &len, outputfileSmart)) != -1)
|
|
{
|
|
string sLine = string(cLine);
|
|
|
|
status = SMART::parseExitStatus(sLine);
|
|
SMART::parseModelFamily(sLine);
|
|
SMART::parseModelName(sLine);
|
|
SMART::parseSerial(sLine);
|
|
SMART::parseCapacity(sLine);
|
|
SMART::parseErrorCount(sLine);
|
|
SMART::parsePowerOnHours(sLine);
|
|
SMART::parsePowerCycle(sLine);
|
|
SMART::parseTemperature(sLine);
|
|
}
|
|
|
|
pclose(outputfileSmart);
|
|
|
|
if (status == 0U)
|
|
{
|
|
// Found S.M.A.R.T. data with this command
|
|
break;
|
|
}
|
|
}
|
|
|
|
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle, temperature); // wirte data in drive
|
|
}
|
|
|
|
/**
|
|
* \brief parse ExitStatus
|
|
* \param string output line of smartctl
|
|
* \return uint_8 exit status
|
|
*/
|
|
uint8_t SMART::parseExitStatus(string sLine)
|
|
{
|
|
uint8_t exitStatus = -1;
|
|
string search("\"exit_status\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 1);
|
|
exitStatus = stol(sLine);
|
|
}
|
|
return exitStatus;
|
|
}
|
|
|
|
/**
|
|
* \brief parse ModelFamiliy
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parseModelFamily(string sLine)
|
|
{
|
|
string search("\"model_family\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 3);
|
|
sLine.erase(sLine.length() - 3, 3);
|
|
modelFamily = sLine;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse ModelName
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parseModelName(string sLine)
|
|
{
|
|
string search("\"model_name\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 3);
|
|
sLine.erase(sLine.length() - 3, 3);
|
|
modelName = sLine;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse Serial
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parseSerial(string sLine)
|
|
{
|
|
string search("\"serial_number\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 3);
|
|
sLine.erase(sLine.length() - 3, 3);
|
|
serial = sLine;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse Capacity
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parseCapacity(string sLine)
|
|
{
|
|
string search("\"bytes\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 2);
|
|
sLine.erase(sLine.length() - 1, 1);
|
|
capacity = stol(sLine);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse ErrorCount
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parseErrorCount(string sLine)
|
|
{
|
|
string search("\"error_count_total\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 2);
|
|
sLine.erase(sLine.length() - 2, 2);
|
|
errorCount = stol(sLine);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse PowerOnHours
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parsePowerOnHours(string sLine)
|
|
{
|
|
string search("\"hours\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 2);
|
|
sLine.erase(sLine.length() - 1, 1);
|
|
powerOnHours = stol(sLine);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse PowerCycle
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parsePowerCycle(string sLine)
|
|
{
|
|
string search("\"power_cycle_count\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 2);
|
|
sLine.erase(sLine.length() - 2, 2);
|
|
powerCycle = stol(sLine);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief parse temperature
|
|
* \param string output line of smartctl
|
|
* \return void
|
|
*/
|
|
void SMART::parseTemperature(string sLine)
|
|
{
|
|
string search("\"current\": ");
|
|
size_t found = sLine.find(search);
|
|
if (found != string::npos)
|
|
{
|
|
sLine.erase(0, sLine.find(": ") + 2);
|
|
sLine.erase(sLine.length() - 1, 2);
|
|
if (sLine == "{")
|
|
{
|
|
temperature = 0U; // this drive doesn't support temperature
|
|
}
|
|
else
|
|
{
|
|
temperature = stol(sLine);
|
|
}
|
|
}
|
|
}
|