/** * @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; } }