/* SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho SPDX-FileCopyrightText: 2018-2020 Andrius Štikonas SPDX-License-Identifier: GPL-3.0-or-later */ #include "core/smartdiskinformation.h" #include "core/smartattributeparseddata.h" #include #include static quint64 u64log2(quint64 n); /** Creates a new SmartDiskInformationObject */ SmartDiskInformation::SmartDiskInformation() : m_ModelName(QString()), m_FirmwareVersion(QString()), m_SerialNumber(QString()), m_Sectors(0), m_Temperature(0), m_BadSectors(0), m_PoweredOn(0), m_PowerCycles(0), m_SmartStatus(false), m_BadAttributeNow(false), m_BadAttributeInThePast(false), m_SelfTestExecutionStatus(SmartStatus::SelfTestStatus::Success), 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() { std::unique_ptr reallocatedSectorCt(findAttribute(5)); std::unique_ptr 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 = SmartStatus::Overall::Bad; return; } quint64 sector_threshold = u64log2(sectors()) * 1024; if (badSectors() >= sector_threshold) { m_Overall = SmartStatus::Overall::BadSectorsMany; return; } validateBadAttributes(); if (m_BadAttributeNow) { m_Overall = SmartStatus::Overall::BadNow; return; } if (badSectors() > 0) { m_Overall = SmartStatus::Overall::BadSectors; return; } if (m_BadAttributeInThePast) { m_Overall = SmartStatus::Overall::BadPast; return; } 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() { std::unique_ptr temperatureCelsius(findAttribute(231)); std::unique_ptr temperatureCelsius2(findAttribute(194)); std::unique_ptr 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() { std::unique_ptr powerOnHours(findAttribute(9)); std::unique_ptr 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() { std::unique_ptr 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 : std::as_const(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 : std::as_const(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; }