diff --git a/src/core/smartdiskinformation.cpp b/src/core/smartdiskinformation.cpp index cc18c7c..3be06cb 100644 --- a/src/core/smartdiskinformation.cpp +++ b/src/core/smartdiskinformation.cpp @@ -1,209 +1,208 @@ /************************************************************************* * Copyright (C) 2018 by Caio Carvalho * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "core/smartdiskinformation.h" #include "core/smartattributeparseddata.h" static quint64 u64log2(quint64 n); /** Creates a new SmartDiskInformationObject */ SmartDiskInformation::SmartDiskInformation() : m_ModelName(QString()), m_FirmwareVersion(QString()), m_SerialNumber(QString()), m_Size(0), m_Temperature(0), m_BadSectors(0), m_PoweredOn(0), m_PowerCycles(0), m_SmartStatus(false), m_BadAttributeNow(false), m_BadAttributeInThePast(false), m_SelfTestExecutionStatus(SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER), - m_Overall(SmartDiskInformation::Overall::BadStatus) + m_Overall(SmartStatus::Overall::Bad) { - } /** Update the number of bad sectors based on reallocated sector count and current pending sector attributes data */ void SmartDiskInformation::updateBadSectors() { SmartAttributeParsedData *reallocatedSectorCt; reallocatedSectorCt = findAttribute(5); SmartAttributeParsedData *currentPendingSector; currentPendingSector = findAttribute(197); if (!reallocatedSectorCt && !currentPendingSector) m_BadSectors = 0; else if (reallocatedSectorCt && currentPendingSector) m_BadSectors = reallocatedSectorCt->prettyValue() + currentPendingSector->prettyValue(); else if (reallocatedSectorCt) m_BadSectors = reallocatedSectorCt->prettyValue(); else m_BadSectors = currentPendingSector->prettyValue(); } /** Update SMART overall data based on the quantity of bad sectors and the status of SMART attributes */ void SmartDiskInformation::updateOverall() { if (!smartStatus()) { - m_Overall = Overall::BadStatus; + m_Overall = SmartStatus::Overall::Bad; return; } quint64 sector_threshold = u64log2(size() / 512) * 1024; if (badSectors() >= sector_threshold) { - m_Overall = Overall::BadSectorsMany; + m_Overall = SmartStatus::Overall::BadSectorsMany; return; } validateBadAttributes(); if (m_BadAttributeNow) { - m_Overall = Overall::BadAttributeNow; + m_Overall = SmartStatus::Overall::BadNow; return; } if (badSectors() > 0) { - m_Overall = Overall::BadSector; + m_Overall = SmartStatus::Overall::BadSectors; return; } if (m_BadAttributeInThePast) { - m_Overall = Overall::BadAttributeInThePast; + m_Overall = SmartStatus::Overall::BadPast; return; } - m_Overall = Overall::Good; + m_Overall = SmartStatus::Overall::Good; } /** Update the temperature value based on SMART attributes @return a boolean representing the status of the operation */ bool SmartDiskInformation::updateTemperature() { SmartAttributeParsedData *temperatureCelsius; SmartAttributeParsedData *temperatureCelsius2; SmartAttributeParsedData *airflowTemperatureCelsius; temperatureCelsius = findAttribute(231); temperatureCelsius2 = findAttribute(194); airflowTemperatureCelsius = findAttribute(190); if (temperatureCelsius != nullptr && temperatureCelsius->prettyUnit() == SmartAttributeUnit::Milikelvin) { m_Temperature = temperatureCelsius->prettyValue(); return true; } else if (temperatureCelsius2 != nullptr && temperatureCelsius2->prettyUnit() == SmartAttributeUnit::Milikelvin) { m_Temperature = temperatureCelsius2->prettyValue(); return true; } else if (airflowTemperatureCelsius != nullptr && airflowTemperatureCelsius->prettyUnit() == SmartAttributeUnit::Milikelvin) { m_Temperature = airflowTemperatureCelsius->prettyValue(); return true; } return false; } /** Update the powered on value based on SMART attributes @return a boolean representing the status of the operation */ bool SmartDiskInformation::updatePowerOn() { SmartAttributeParsedData *powerOnHours; SmartAttributeParsedData *powerOnSeconds; powerOnHours = findAttribute(9); powerOnSeconds = findAttribute(233); if (powerOnHours != nullptr && powerOnHours->prettyUnit() == SmartAttributeUnit::Miliseconds) { m_PoweredOn = powerOnHours->prettyValue(); return true; } else if (powerOnSeconds != nullptr && powerOnSeconds->prettyUnit() == SmartAttributeUnit::Miliseconds) { m_PoweredOn = powerOnSeconds->prettyValue(); return true; } return false; } /** Update the power cycles value based on SMART attributes @return a boolean representing the status of the operation */ bool SmartDiskInformation::updatePowerCycle() { SmartAttributeParsedData *powerCycleCount; powerCycleCount = findAttribute(12); if (powerCycleCount != nullptr && powerCycleCount->prettyUnit() == SmartAttributeUnit::None) { m_PowerCycles = powerCycleCount->prettyValue(); return true; } return false; } /** Validate disk attributes status */ void SmartDiskInformation::validateBadAttributes() { for (const SmartAttributeParsedData &attribute : qAsConst(m_Attributes)) { if (attribute.prefailure()) { if (attribute.goodNowValid() && !attribute.goodNow()) m_BadAttributeNow = true; if (attribute.goodInThePastValid() && !attribute.goodInThePast()) m_BadAttributeInThePast = true; } } } /** Search for a attribute based on its id number @return a reference to the attribute */ SmartAttributeParsedData *SmartDiskInformation::findAttribute(quint32 id) { SmartAttributeParsedData *attr = nullptr; for (const SmartAttributeParsedData &attribute : qAsConst(m_Attributes)) { if (id == attribute.id()) { attr = new SmartAttributeParsedData(attribute); break; } } return attr; } static quint64 u64log2(quint64 n) { quint64 r; if (n <= 1) return 0; r = 0; for (;;) { n = n >> 1; if (!n) return r; r++; } return 0; } diff --git a/src/core/smartdiskinformation.h b/src/core/smartdiskinformation.h index 4c55f41..e1593c0 100644 --- a/src/core/smartdiskinformation.h +++ b/src/core/smartdiskinformation.h @@ -1,199 +1,192 @@ /************************************************************************* * Copyright (C) 2018 by Caio Carvalho * + * Copyright (C) 2018 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #ifndef KPMCORE_SMARTDISKINFORMATION_H #define KPMCORE_SMARTDISKINFORMATION_H +#include "core/smartstatus.h" + #include #include class SmartAttributeParsedData; /** Disk information retrieved by SMART. It includes a list with your SMART attributes. @author Caio Carvalho */ class SmartDiskInformation { public: /** SMART self test execution state */ enum SmartSelfTestExecutionStatus { SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER = 0, SMART_SELF_TEST_EXECUTION_STATUS_ABORTED = 1, SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED = 2, SMART_SELF_TEST_EXECUTION_STATUS_FATAL = 3, SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN = 4, SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL = 5, SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO = 6, SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ = 7, SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING = 8, SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS = 15, _SMART_SELF_TEST_EXECUTION_STATUS_MAX }; - /** SMART overall state */ - enum class Overall { - Good, - BadAttributeInThePast, - BadSector, - BadAttributeNow, - BadSectorsMany, - BadStatus, - }; - public: SmartDiskInformation(); public: void updateBadSectors(); void updateOverall(); bool updateTemperature(); bool updatePowerOn(); bool updatePowerCycle(); SmartAttributeParsedData *findAttribute(quint32 id); public: const QString model() const { return m_ModelName; /**< @return the disk model name */ } const QString firmware() const { return m_FirmwareVersion; /**< @return the disk firmware version */ } const QString serial() const { return m_SerialNumber; /**< @return the disk serial number */ } quint64 size() const { return m_Size; /**< @return disk size */ } bool smartStatus() const { return m_SmartStatus; /**< @return a boolean representing SMART status */ } SmartSelfTestExecutionStatus selfTestExecutionStatus() const { return m_SelfTestExecutionStatus; /**< @return SMART self execution status */ } - Overall overall() const + SmartStatus::Overall overall() const { return m_Overall; /**< @return SMART overall status */ } quint64 temperature() const { return m_Temperature; /**< @return disk temperature in kelvin */ } quint64 badSectors() const { return m_BadSectors; /**< @return the number of bad sectors */ } quint64 poweredOn() const { return m_PoweredOn; /**< @return quantity of time that device is powered on */ } quint64 powerCycles() const { return m_PowerCycles; /**< @return quantity of power cycles */ } QList attributes() const { return m_Attributes; /**< @return a list that contains the disk SMART attributes */ } public: void setModel(QString modelName) { m_ModelName = modelName; } void setFirmware(QString firmware) { m_FirmwareVersion = firmware; } void setSerial(QString serial) { m_SerialNumber = serial; } void setSize(quint64 size) { m_Size = size; } void setPowerCycles(quint64 powerCycleCt) { m_PowerCycles = powerCycleCt; } void setSmartStatus(bool smartStatus) { m_SmartStatus = smartStatus; } void setSelfTestExecutionStatus(SmartSelfTestExecutionStatus status) { m_SelfTestExecutionStatus = status; } void addAttribute(SmartAttributeParsedData &attribute) { m_Attributes << attribute; } protected: void validateBadAttributes(); private: QString m_ModelName; QString m_FirmwareVersion; QString m_SerialNumber; quint64 m_Size; quint64 m_Temperature; quint64 m_BadSectors; quint64 m_PoweredOn; quint64 m_PowerCycles; bool m_SmartStatus; bool m_BadAttributeNow; bool m_BadAttributeInThePast; SmartSelfTestExecutionStatus m_SelfTestExecutionStatus; - Overall m_Overall; + SmartStatus::Overall m_Overall; QList m_Attributes; }; #endif // SMARTDISKINFORMATION_H diff --git a/src/core/smartstatus.cpp b/src/core/smartstatus.cpp index 855d99a..0e67cde 100644 --- a/src/core/smartstatus.cpp +++ b/src/core/smartstatus.cpp @@ -1,238 +1,212 @@ /************************************************************************* * Copyright (C) 2010 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "core/smartstatus.h" #include "core/smartparser.h" #include "core/smartdiskinformation.h" #include "core/smartattributeparseddata.h" #include #include #include #include #include SmartStatus::SmartStatus(const QString &device_path) : m_DevicePath(device_path), m_InitSuccess(false), m_Status(false), m_ModelName(), m_Serial(), m_Firmware(), m_Overall(Overall::Bad), m_SelfTestStatus(SelfTestStatus::Success), m_Temp(0), m_BadSectors(0), m_PowerCycles(0), m_PoweredOn(0) { update(); } void SmartStatus::update() { SmartParser parser(devicePath()); if (!parser.init()) { qDebug() << "error during smart output parsing for " << devicePath() << ": " << strerror(errno); return; } SmartDiskInformation *disk; disk = parser.diskInformation(); if (!disk) return; setStatus(disk->smartStatus()); setModelName(disk->model()); setFirmware(disk->firmware()); setSerial(disk->serial()); switch (disk->selfTestExecutionStatus()) { case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ABORTED: setSelfTestStatus(SelfTestStatus::Aborted); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED: setSelfTestStatus(SelfTestStatus::Interrupted); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_FATAL: setSelfTestStatus(SelfTestStatus::Fatal); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN: setSelfTestStatus(SelfTestStatus::ErrorUnknown); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL: setSelfTestStatus(SelfTestStatus::ErrorEletrical); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO: setSelfTestStatus(SelfTestStatus::ErrorServo); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ: setSelfTestStatus(SelfTestStatus::ErrorRead); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING: setSelfTestStatus(SelfTestStatus::ErrorHandling); break; case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS: setSelfTestStatus(SelfTestStatus::InProgress); break; default: case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER: setSelfTestStatus(SelfTestStatus::Success); break; } - switch (disk->overall()) { - case SmartDiskInformation::Overall::Good: - setOverall(Overall::Good); - break; - - case SmartDiskInformation::Overall::BadAttributeInThePast: - setOverall(Overall::BadPast); - break; - - case SmartDiskInformation::Overall::BadSector: - setOverall(Overall::BadSectors); - break; - - case SmartDiskInformation::Overall::BadAttributeNow: - setOverall(Overall::BadNow); - break; - - case SmartDiskInformation::Overall::BadSectorsMany: - setOverall(Overall::BadSectorsMany); - break; - - default: - case SmartDiskInformation::Overall::BadStatus: - setOverall(Overall::Bad); - break; - - } + setOverall(disk->overall()); setTemp(disk->temperature()); setBadSectors(disk->badSectors()); setPoweredOn(disk->poweredOn()); setPowerCycles(disk->powerCycles()); addAttributes(disk->attributes()); setInitSuccess(true); } QString SmartStatus::tempToString(quint64 mkelvin) { const double celsius = (mkelvin - 273150.0) / 1000.0; const double fahrenheit = 9.0 * celsius / 5.0 + 32; return xi18nc("@item:intable degrees in Celsius and Fahrenheit", "%1° C / %2° F", QLocale().toString(celsius, 1), QLocale().toString(fahrenheit, 1)); } QString SmartStatus::selfTestStatusToString(SmartStatus::SelfTestStatus s) { switch (s) { case SelfTestStatus::Aborted: return xi18nc("@item", "Aborted"); case SelfTestStatus::Interrupted: return xi18nc("@item", "Interrupted"); case SelfTestStatus::Fatal: return xi18nc("@item", "Fatal error"); case SelfTestStatus::ErrorUnknown: return xi18nc("@item", "Unknown error"); case SelfTestStatus::ErrorEletrical: return xi18nc("@item", "Electrical error"); case SelfTestStatus::ErrorServo: return xi18nc("@item", "Servo error"); case SelfTestStatus::ErrorRead: return xi18nc("@item", "Read error"); case SelfTestStatus::ErrorHandling: return xi18nc("@item", "Handling error"); case SelfTestStatus::InProgress: return xi18nc("@item", "Self test in progress"); case SelfTestStatus::Success: default: return xi18nc("@item", "Success"); } } QString SmartStatus::overallAssessmentToString(Overall o) { switch (o) { case Overall::Good: return xi18nc("@item", "Healthy"); case Overall::BadPast: return xi18nc("@item", "Has been used outside of its design parameters in the past."); case Overall::BadSectors: return xi18nc("@item", "Has some bad sectors."); case Overall::BadNow: return xi18nc("@item", "Is being used outside of its design parameters right now."); case Overall::BadSectorsMany: return xi18nc("@item", "Has many bad sectors."); case Overall::Bad: default: return xi18nc("@item", "Disk failure is imminent. Backup all data!"); } } void SmartStatus::addAttributes(QList attr) { m_Attributes.clear(); for (const SmartAttributeParsedData &at : qAsConst(attr)) { SmartAttribute sm(at); m_Attributes.append(sm); } }