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 }