File indexing completed on 2024-04-28 05:45:47

0001 /*
0002     SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
0003     SPDX-FileCopyrightText: 2018-2020 Andrius Štikonas <andrius@stikonas.eu>
0004 
0005     SPDX-License-Identifier: GPL-3.0-or-later
0006 */
0007 
0008 #include "core/smartdiskinformation.h"
0009 #include "core/smartattributeparseddata.h"
0010 
0011 #include <memory>
0012 #include <utility>
0013 
0014 static quint64 u64log2(quint64 n);
0015 
0016 /** Creates a new SmartDiskInformationObject */
0017 SmartDiskInformation::SmartDiskInformation() :
0018     m_ModelName(QString()),
0019     m_FirmwareVersion(QString()),
0020     m_SerialNumber(QString()),
0021     m_Sectors(0),
0022     m_Temperature(0),
0023     m_BadSectors(0),
0024     m_PoweredOn(0),
0025     m_PowerCycles(0),
0026     m_SmartStatus(false),
0027     m_BadAttributeNow(false),
0028     m_BadAttributeInThePast(false),
0029     m_SelfTestExecutionStatus(SmartStatus::SelfTestStatus::Success),
0030     m_Overall(SmartStatus::Overall::Bad)
0031 {
0032 }
0033 
0034 /** Update the number of bad sectors based on reallocated sector count and current pending sector attributes data */
0035 void SmartDiskInformation::updateBadSectors()
0036 {
0037     std::unique_ptr<SmartAttributeParsedData> reallocatedSectorCt(findAttribute(5));
0038     std::unique_ptr<SmartAttributeParsedData> currentPendingSector(findAttribute(197));
0039 
0040     if (!reallocatedSectorCt && !currentPendingSector)
0041         m_BadSectors = 0;
0042     else if (reallocatedSectorCt && currentPendingSector)
0043         m_BadSectors = reallocatedSectorCt->prettyValue() + currentPendingSector->prettyValue();
0044     else if (reallocatedSectorCt)
0045         m_BadSectors = reallocatedSectorCt->prettyValue();
0046     else
0047         m_BadSectors = currentPendingSector->prettyValue();
0048 }
0049 
0050 /** Update SMART overall data based on the quantity of bad sectors and the status of SMART attributes */
0051 void SmartDiskInformation::updateOverall()
0052 {
0053     if (!smartStatus()) {
0054         m_Overall = SmartStatus::Overall::Bad;
0055         return;
0056     }
0057 
0058     quint64 sector_threshold = u64log2(sectors()) * 1024;
0059 
0060     if (badSectors() >= sector_threshold) {
0061         m_Overall = SmartStatus::Overall::BadSectorsMany;
0062         return;
0063     }
0064 
0065     validateBadAttributes();
0066 
0067     if (m_BadAttributeNow) {
0068         m_Overall = SmartStatus::Overall::BadNow;
0069         return;
0070     }
0071 
0072     if (badSectors() > 0) {
0073         m_Overall = SmartStatus::Overall::BadSectors;
0074         return;
0075     }
0076 
0077     if (m_BadAttributeInThePast) {
0078         m_Overall = SmartStatus::Overall::BadPast;
0079         return;
0080     }
0081 
0082     m_Overall = SmartStatus::Overall::Good;
0083 }
0084 
0085 /** Update the temperature value based on SMART attributes
0086     @return a boolean representing the status of the operation
0087 */
0088 bool SmartDiskInformation::updateTemperature()
0089 {
0090     std::unique_ptr<SmartAttributeParsedData> temperatureCelsius(findAttribute(231));
0091     std::unique_ptr<SmartAttributeParsedData> temperatureCelsius2(findAttribute(194));
0092     std::unique_ptr<SmartAttributeParsedData> airflowTemperatureCelsius(findAttribute(190));
0093 
0094     if (temperatureCelsius != nullptr
0095             && temperatureCelsius->prettyUnit() == SmartAttributeUnit::Milikelvin) {
0096         m_Temperature = temperatureCelsius->prettyValue();
0097         return true;
0098     } else if (temperatureCelsius2 != nullptr
0099                && temperatureCelsius2->prettyUnit() == SmartAttributeUnit::Milikelvin) {
0100         m_Temperature = temperatureCelsius2->prettyValue();
0101         return true;
0102     } else if (airflowTemperatureCelsius != nullptr
0103                && airflowTemperatureCelsius->prettyUnit() ==
0104                SmartAttributeUnit::Milikelvin) {
0105         m_Temperature = airflowTemperatureCelsius->prettyValue();
0106         return true;
0107     }
0108     return false;
0109 }
0110 
0111 /** Update the powered on value based on SMART attributes
0112     @return a boolean representing the status of the operation
0113 */
0114 bool SmartDiskInformation::updatePowerOn()
0115 {
0116     std::unique_ptr<SmartAttributeParsedData> powerOnHours(findAttribute(9));
0117     std::unique_ptr<SmartAttributeParsedData> powerOnSeconds(findAttribute(233));
0118 
0119     if (powerOnHours != nullptr
0120             && powerOnHours->prettyUnit() == SmartAttributeUnit::Miliseconds) {
0121         m_PoweredOn = powerOnHours->prettyValue();
0122         return true;
0123     } else if (powerOnSeconds != nullptr
0124                && powerOnSeconds->prettyUnit() == SmartAttributeUnit::Miliseconds) {
0125         m_PoweredOn = powerOnSeconds->prettyValue();
0126         return true;
0127     }
0128     return false;
0129 }
0130 
0131 /** Update the power cycles value based on SMART attributes
0132     @return a boolean representing the status of the operation
0133 */
0134 bool SmartDiskInformation::updatePowerCycle()
0135 {
0136     std::unique_ptr<SmartAttributeParsedData> powerCycleCount(findAttribute(12));
0137 
0138     if (powerCycleCount != nullptr
0139             && powerCycleCount->prettyUnit() == SmartAttributeUnit::None) {
0140         m_PowerCycles = powerCycleCount->prettyValue();
0141         return true;
0142     }
0143     return false;
0144 }
0145 
0146 /** Validate disk attributes status */
0147 void SmartDiskInformation::validateBadAttributes()
0148 {
0149     for (const SmartAttributeParsedData &attribute : std::as_const(m_Attributes)) {
0150         if (attribute.prefailure()) {
0151             if (attribute.goodNowValid() && !attribute.goodNow())
0152                 m_BadAttributeNow = true;
0153             if (attribute.goodInThePastValid() && !attribute.goodInThePast())
0154                 m_BadAttributeInThePast = true;
0155         }
0156     }
0157 }
0158 
0159 /** Search for a attribute based on its id number
0160     @return a reference to the attribute
0161 */
0162 SmartAttributeParsedData *SmartDiskInformation::findAttribute(quint32 id)
0163 {
0164     SmartAttributeParsedData *attr = nullptr;
0165     for (const SmartAttributeParsedData &attribute : std::as_const(m_Attributes)) {
0166         if (id == attribute.id()) {
0167             attr = new SmartAttributeParsedData(attribute);
0168             break;
0169         }
0170     }
0171     return attr;
0172 }
0173 
0174 static quint64 u64log2(quint64 n)
0175 {
0176     quint64 r;
0177 
0178     if (n <= 1)
0179         return 0;
0180 
0181     r = 0;
0182     for (;;) {
0183         n = n >> 1;
0184         if (!n)
0185             return r;
0186         r++;
0187     }
0188     return 0;
0189 }