reHDD/src/smart.cpp
2024-06-02 09:31:55 +02:00

286 lines
6.9 KiB
C++

/**
* @file smart.cpp
* @brief read S.M.A.R.T values
* @author hendrik schutter
* @date 01.05.2020
*/
#include "../include/reHDD.h"
/**
* \brief get and set S.M.A.R.T. values in Drive
* \param pointer of Drive instance
* \return void
*/
void SMART::readSMARTData(Drive *drive)
{
string modelFamily;
string modelName;
string serial;
uint64_t capacity = 0U;
uint32_t errorCount = 0U;
uint32_t powerOnHours = 0U;
uint32_t powerCycles = 0U;
uint32_t temperature = 0U;
modelFamily.clear();
modelName.clear();
serial.clear();
string sSmartctlCommands[] = {" --json -a ", " --json -d sntjmicron -a ", " --json -d sntasmedia -a ", " --json -d sntrealtek -a ", " --json -d sat -a "};
for (string sSmartctlCommand : sSmartctlCommands)
{
string sCMD = ("smartctl");
sCMD.append(sSmartctlCommand);
sCMD.append(drive->getPath());
const char *cpComand = sCMD.c_str();
//Logger::logThis()->info(cpComand);
FILE *outputfileSmart = popen(cpComand, "r");
size_t len = 0U; // length of found line
char *cLine = NULL; // found line
uint8_t status = 255U;
while ((getline(&cLine, &len, outputfileSmart)) != -1)
{
string sLine = string(cLine);
SMART::parseExitStatus(sLine, status);
SMART::parseModelFamily(sLine, modelFamily);
SMART::parseModelName(sLine, modelName);
SMART::parseSerial(sLine, serial);
SMART::parseCapacity(sLine, capacity);
SMART::parseErrorCount(sLine, errorCount);
SMART::parsePowerOnHours(sLine, powerOnHours);
SMART::parsePowerCycles(sLine, powerCycles);
SMART::parseTemperature(sLine, temperature);
}
pclose(outputfileSmart);
if (status == 0U)
{
// Found S.M.A.R.T. data with this command
//Logger::logThis()->info("Found S.M.A.R.T. data with this command");
break;
}
}
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycles, temperature); // write data in drive
}
/**
* \brief parse ExitStatus
* \param string output line of smartctl
* \param uint8_t parsed status
* \return bool if parsing was possible
*/
bool SMART::parseExitStatus(string sLine, uint8_t &status)
{
string search("\"exit_status\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0U, sLine.find(": ") + 1U);
status = stol(sLine);
return true;
}
else
{
return false;
}
}
/**
* \brief parse ModelFamily
* \param string output line of smartctl
* \param string parsed model family
* \return bool if parsing was possible
*/
bool SMART::parseModelFamily(string sLine, string &modelFamily)
{
string search("\"model_family\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0U, sLine.find(": ") + 3U);
sLine.erase(sLine.length() - 3U, 3U);
modelFamily = sLine;
return true;
}
else
{
return false;
}
}
/**
* \brief parse ModelName
* \param string output line of smartctl
* \param string parsed model name
* \return bool if parsing was possible
*/
bool SMART::parseModelName(string sLine, string &modelName)
{
string search("\"model_name\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0U, sLine.find(": ") + 3U);
sLine.erase(sLine.length() - 3U, 3U);
modelName = sLine;
return true;
}
else
{
return false;
}
}
/**
* \brief parse Serial
* \param string output line of smartctl
* \param string parsed serial
* \return bool if parsing was possible
*/
bool SMART::parseSerial(string sLine, string &serial)
{
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;
return true;
}
else
{
return false;
}
}
/**
* \brief parse Capacity
* \param string output line of smartctl
* \param string parsed capacity
* \return bool if parsing was possible
*/
bool SMART::parseCapacity(string sLine, uint64_t &capacity)
{
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);
return true;
}
else
{
return false;
}
}
/**
* \brief parse ErrorCount
* \param string output line of smartctl
* \param uint32_t parsed error count
* \return bool if parsing was possible
*/
bool SMART::parseErrorCount(string sLine, uint32_t &errorCount)
{
string search("\"error_count_total\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0U, sLine.find(": ") + 2U);
sLine.erase(sLine.length() - 2U, 2U);
errorCount = stol(sLine);
return true;
}
else
{
return false;
}
}
/**
* \brief parse PowerOnHours
* \param string output line of smartctl\
* \param uint32_t parsed power on hours
* \return bool if parsing was possible
*/
bool SMART::parsePowerOnHours(string sLine, uint32_t &powerOnHours)
{
string search("\"hours\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0U, sLine.find(": ") + 2U);
sLine.erase(sLine.length() - 1U, 1U);
powerOnHours = stol(sLine);
return true;
}
else
{
return false;
}
}
/**
* \brief parse PowerCycle
* \param string output line of smartctl
* \param uint32_t parsed power cycles
* \return bool if parsing was possible
*/
bool SMART::parsePowerCycles(string sLine, uint32_t &powerCycles)
{
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);
powerCycles = stol(sLine);
return true;
}
else
{
return false;
}
}
/**
* \brief parse temperature
* \param string output line of smartctl
* \param uint32_t parsed temperature
* \return bool if parsing was possible
*/
bool SMART::parseTemperature(string sLine, uint32_t &temperature)
{
string search("\"current\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0U, sLine.find(": ") + 2U);
sLine.erase(sLine.length() - 1U, 2U);
if (sLine == "{")
{
temperature = 0U; // this drive doesn't support temperature
}
else
{
temperature = stol(sLine);
}
return true;
}
else
{
return false;
}
}