kpmcore/src/core/smartdiskinformation.cpp

190 lines
5.8 KiB
C++

/*
SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
SPDX-FileCopyrightText: 2018-2020 Andrius Štikonas <andrius@stikonas.eu>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "core/smartdiskinformation.h"
#include "core/smartattributeparseddata.h"
#include <memory>
#include <utility>
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<SmartAttributeParsedData> reallocatedSectorCt(findAttribute(5));
std::unique_ptr<SmartAttributeParsedData> 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<SmartAttributeParsedData> temperatureCelsius(findAttribute(231));
std::unique_ptr<SmartAttributeParsedData> temperatureCelsius2(findAttribute(194));
std::unique_ptr<SmartAttributeParsedData> 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<SmartAttributeParsedData> powerOnHours(findAttribute(9));
std::unique_ptr<SmartAttributeParsedData> 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<SmartAttributeParsedData> 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;
}