Merge branch 'smart' into kauth
This commit is contained in:
commit
790553aa0b
|
@ -80,7 +80,6 @@ kde_enable_exceptions()
|
|||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(BLKID REQUIRED blkid>=2.30)
|
||||
pkg_check_modules(LIBATASMART REQUIRED libatasmart)
|
||||
|
||||
include_directories(${Qt5Core_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${BLKID_INCLUDE_DIRS} lib/ src/)
|
||||
|
||||
|
|
|
@ -7,7 +7,5 @@ set(BACKEND_SRC
|
|||
|
||||
set(BACKEND_LIB_HDRS
|
||||
backend/corebackend.h
|
||||
backend/corebackenddevice.h
|
||||
backend/corebackendmanager.h
|
||||
backend/corebackendpartitiontable.h
|
||||
)
|
||||
|
|
|
@ -20,6 +20,9 @@ set(CORE_SRC
|
|||
core/partitiontable.cpp
|
||||
core/smartstatus.cpp
|
||||
core/smartattribute.cpp
|
||||
core/smartparser.cpp
|
||||
core/smartattributeparseddata.cpp
|
||||
core/smartdiskinformation.cpp
|
||||
core/volumemanagerdevice.cpp
|
||||
)
|
||||
|
||||
|
@ -38,6 +41,9 @@ set(CORE_LIB_HDRS
|
|||
core/partitiontable.h
|
||||
core/smartattribute.h
|
||||
core/smartstatus.h
|
||||
core/smartparser.h
|
||||
core/smartattributeparseddata.h
|
||||
core/smartdiskinformation.h
|
||||
core/volumemanagerdevice.h
|
||||
)
|
||||
|
||||
|
|
|
@ -18,33 +18,33 @@
|
|||
|
||||
#include "core/smartattribute.h"
|
||||
#include "core/smartstatus.h"
|
||||
#include "core/smartattributeparseddata.h"
|
||||
|
||||
#include <QLocale>
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KFormat>
|
||||
|
||||
#include <atasmart.h>
|
||||
|
||||
static QString getAttrName(qint32 id);
|
||||
static QString getAttrDescription(qint32 id);
|
||||
static QString getPrettyValue(quint64 value, qint64 unit);
|
||||
static SmartAttribute::Assessment getAssessment(const SkSmartAttributeParsedData* a);
|
||||
static QString getRaw(const uint8_t*);
|
||||
static SmartAttribute::Assessment getAssessment(const SmartAttributeParsedData& a);
|
||||
static QString getRaw(quint64 raw);
|
||||
|
||||
SmartAttribute::SmartAttribute(const SkSmartAttributeParsedData* a) :
|
||||
m_Id(a->id),
|
||||
m_Name(getAttrName(a->id)),
|
||||
m_Desc(getAttrDescription(a->id)),
|
||||
m_FailureType(a->prefailure ? PreFailure : OldAge),
|
||||
m_UpdateType(a->online ? Online : Offline),
|
||||
m_Current(a->current_value_valid ? a->current_value : -1),
|
||||
m_Worst(a->worst_value_valid ? a->worst_value : -1),
|
||||
m_Threshold(a->threshold_valid ? a->threshold : -1),
|
||||
m_Raw(getRaw(a->raw)),
|
||||
SmartAttribute::SmartAttribute(const SmartAttributeParsedData& a) :
|
||||
m_Id(a.id()),
|
||||
m_Name(getAttrName(a.id())),
|
||||
m_Desc(getAttrDescription(a.id())),
|
||||
m_FailureType(a.prefailure() ? PreFailure : OldAge),
|
||||
m_UpdateType(a.online() ? Online : Offline),
|
||||
m_Current(a.currentValueValid() ? a.currentValue() : -1),
|
||||
m_Worst(a.worstValueValid() ? a.worstValue() : -1),
|
||||
m_Threshold(a.thresholdValid() ? a.threshold() : -1),
|
||||
m_Raw(getRaw(a.raw())),
|
||||
m_Assessment(getAssessment(a)),
|
||||
m_Value(getPrettyValue(a->pretty_value, a->pretty_unit))
|
||||
m_Value(getPrettyValue(a.prettyValue(), a.prettyUnit()))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString SmartAttribute::assessmentToString(Assessment a)
|
||||
|
@ -73,23 +73,23 @@ static QString getPrettyValue(quint64 value, qint64 unit)
|
|||
QString rval;
|
||||
|
||||
switch (unit) {
|
||||
case SK_SMART_ATTRIBUTE_UNIT_MSECONDS:
|
||||
case SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS:
|
||||
rval = KFormat().formatDuration(value);
|
||||
break;
|
||||
|
||||
case SK_SMART_ATTRIBUTE_UNIT_SECTORS:
|
||||
case SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_SECTORS:
|
||||
rval = xi18ncp("@item:intable", "%1 sector", "%1 sectors", value);
|
||||
break;
|
||||
|
||||
case SK_SMART_ATTRIBUTE_UNIT_MKELVIN:
|
||||
case SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN:
|
||||
rval = SmartStatus::tempToString(value);
|
||||
break;
|
||||
|
||||
case SK_SMART_ATTRIBUTE_UNIT_NONE:
|
||||
case SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE:
|
||||
rval = QLocale().toString(value);
|
||||
break;
|
||||
|
||||
case SK_SMART_ATTRIBUTE_UNIT_UNKNOWN:
|
||||
case SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN:
|
||||
default:
|
||||
rval = xi18nc("@item:intable not applicable", "N/A");
|
||||
break;
|
||||
|
@ -214,23 +214,23 @@ static QString getAttrDescription(qint32 id)
|
|||
return QString();
|
||||
}
|
||||
|
||||
static SmartAttribute::Assessment getAssessment(const SkSmartAttributeParsedData* a)
|
||||
static SmartAttribute::Assessment getAssessment(const SmartAttributeParsedData& a)
|
||||
{
|
||||
SmartAttribute::Assessment rval = SmartAttribute::NotApplicable;
|
||||
|
||||
bool failed = false;
|
||||
bool hasFailed = false;
|
||||
|
||||
if (a->prefailure) {
|
||||
if (a->good_now_valid && !a->good_now)
|
||||
if (a.prefailure()) {
|
||||
if (a.goodNowValid() && !a.goodNow())
|
||||
failed = true;
|
||||
|
||||
if (a->good_in_the_past_valid && !a->good_in_the_past)
|
||||
if (a.goodInThePastValid() && !a.goodInThePast())
|
||||
hasFailed = true;
|
||||
} else if (a->threshold_valid) {
|
||||
if (a->current_value_valid && a->current_value <= a->threshold)
|
||||
} else if (a.thresholdValid()) {
|
||||
if (a.currentValueValid() && a.currentValue() <= a.threshold())
|
||||
failed = true;
|
||||
else if (a->worst_value_valid && a->worst_value <= a->threshold)
|
||||
else if (a.worstValueValid() && a.worstValue() <= a.threshold())
|
||||
hasFailed = true;
|
||||
}
|
||||
|
||||
|
@ -238,19 +238,17 @@ static SmartAttribute::Assessment getAssessment(const SkSmartAttributeParsedData
|
|||
rval = SmartAttribute::Failing;
|
||||
else if (hasFailed)
|
||||
rval = SmartAttribute::HasFailed;
|
||||
else if (a->warn)
|
||||
else if (a.warn())
|
||||
rval = SmartAttribute::Warning;
|
||||
else if (a->good_now_valid)
|
||||
else if (a.goodNowValid())
|
||||
rval = SmartAttribute::Good;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static QString getRaw(const uint8_t* raw)
|
||||
static QString getRaw(quint64 raw)
|
||||
{
|
||||
QString rval = QStringLiteral("0x");
|
||||
for (qint32 i = 5; i >= 0; i--)
|
||||
rval += QStringLiteral("%1").arg(raw[i], 2, 16, QLatin1Char('0'));
|
||||
|
||||
rval += QStringLiteral("%1").arg(raw, 12, 16, QLatin1Char('0'));
|
||||
return rval;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
#define KPMCORE_SMARTATTRIBUTE_H
|
||||
|
||||
#include "util/libpartitionmanagerexport.h"
|
||||
#include "core/smartattributeparseddata.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
struct SkSmartAttributeParsedData;
|
||||
|
||||
class LIBKPMCORE_EXPORT SmartAttribute
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
SmartAttribute(const SkSmartAttributeParsedData* a);
|
||||
SmartAttribute(const SmartAttributeParsedData& a);
|
||||
|
||||
public:
|
||||
qint32 id() const {
|
||||
|
|
|
@ -0,0 +1,655 @@
|
|||
/*************************************************************************
|
||||
* Copyright (C) 2018 by Caio Carvalho <caiojcarvalho@gmail.com> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>.*
|
||||
*************************************************************************/
|
||||
|
||||
#include "smartattributeparseddata.h"
|
||||
#include "core/smartdiskinformation.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QMap>
|
||||
#include <QRegularExpression>
|
||||
#include <QVariant>
|
||||
|
||||
#define MKELVIN_VALID_MIN ((qint64) ((-15LL*1000LL) + 273150LL))
|
||||
#define MKELVIN_VALID_MAX ((qint64) ((100LL*1000LL) + 273150LL))
|
||||
|
||||
#define MSECOND_VALID_MIN 1ULL
|
||||
#define MSECOND_VALID_SHORT_MAX (60ULL * 60ULL * 1000ULL)
|
||||
#define MSECOND_VALID_LONG_MAX (30ULL * 365ULL * 24ULL * 60ULL * 60ULL * 1000ULL)
|
||||
|
||||
static const QMap<qint32, SmartAttributeParsedData::SmartAttributeUnit> tableUnit();
|
||||
static SmartAttributeParsedData::SmartQuirk getQuirk(QString model, QString firmware);
|
||||
|
||||
SmartAttributeParsedData::SmartAttributeParsedData(SmartDiskInformation *disk,
|
||||
QJsonObject jsonAttribute) :
|
||||
m_Id(0),
|
||||
m_CurrentValue(0),
|
||||
m_WorstValue(0),
|
||||
m_Threshold(0),
|
||||
m_Raw(0),
|
||||
m_PrettyValue(0),
|
||||
m_CurrentValueValid(false),
|
||||
m_WorstValueValid(false),
|
||||
m_ThresholdValid(false),
|
||||
m_Prefailure(false),
|
||||
m_Online(false),
|
||||
m_GoodNow(true),
|
||||
m_GoodNowValid(false),
|
||||
m_GoodInThePast(true),
|
||||
m_GoodInThePastValid(false),
|
||||
m_Warn(false),
|
||||
m_PrettyUnit(SMART_ATTRIBUTE_UNIT_UNKNOWN),
|
||||
m_Disk(disk),
|
||||
m_Quirk((SmartAttributeParsedData::SmartQuirk) 0)
|
||||
{
|
||||
if (disk)
|
||||
m_Quirk = getQuirk(disk->model(), disk->firmware());
|
||||
|
||||
if (!jsonAttribute.isEmpty()) {
|
||||
QString id = QString::fromLocal8Bit("id");
|
||||
QString value = QString::fromLocal8Bit("value");
|
||||
QString worst = QString::fromLocal8Bit("worst");
|
||||
QString thresh = QString::fromLocal8Bit("thresh");
|
||||
QString raw = QString::fromLocal8Bit("raw");
|
||||
QString flags = QString::fromLocal8Bit("flags");
|
||||
QString prefailure = QString::fromLocal8Bit("prefailure");
|
||||
QString online = QString::fromLocal8Bit("updated_online");
|
||||
|
||||
m_Id = jsonAttribute[id].toInt();
|
||||
m_CurrentValue = jsonAttribute[value].toInt();
|
||||
m_WorstValue = jsonAttribute[worst].toInt();
|
||||
m_Threshold = jsonAttribute[thresh].toInt();
|
||||
|
||||
QJsonObject rawObj = jsonAttribute[raw].toObject();
|
||||
|
||||
m_Raw = rawObj[value].toVariant().toULongLong();
|
||||
|
||||
QJsonObject flagsObj = jsonAttribute[flags].toObject();
|
||||
|
||||
m_Prefailure = flagsObj[prefailure].toBool();
|
||||
m_Online = flagsObj[online].toBool();
|
||||
|
||||
if (!updateUnit())
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
|
||||
makePretty();
|
||||
|
||||
validateValues();
|
||||
|
||||
verifyAttribute();
|
||||
}
|
||||
}
|
||||
|
||||
SmartAttributeParsedData::SmartAttributeParsedData(const SmartAttributeParsedData &other) :
|
||||
m_Id(other.id()),
|
||||
m_CurrentValue(other.currentValue()),
|
||||
m_WorstValue(other.worstValue()),
|
||||
m_Threshold(other.threshold()),
|
||||
m_Raw(other.raw()),
|
||||
m_PrettyValue(other.prettyValue()),
|
||||
m_CurrentValueValid(other.currentValueValid()),
|
||||
m_WorstValueValid(other.worstValueValid()),
|
||||
m_ThresholdValid(other.thresholdValid()),
|
||||
m_Prefailure(other.prefailure()),
|
||||
m_Online(other.online()),
|
||||
m_GoodNow(other.goodNow()),
|
||||
m_GoodNowValid(other.goodNowValid()),
|
||||
m_GoodInThePast(other.goodInThePast()),
|
||||
m_GoodInThePastValid(other.goodInThePastValid()),
|
||||
m_Warn(other.warn()),
|
||||
m_PrettyUnit(other.prettyUnit()),
|
||||
m_Disk(other.disk()),
|
||||
m_Quirk(other.m_Quirk)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::validateValues()
|
||||
{
|
||||
m_CurrentValueValid = m_CurrentValue >= 1 && m_CurrentValue <= 0xFD;
|
||||
m_WorstValueValid = m_WorstValue >= 1 && m_WorstValue <= 0xFD;
|
||||
m_ThresholdValid = m_Threshold != 0xFE;
|
||||
|
||||
if (m_Threshold >= 1 && m_Threshold <= 0xFD) {
|
||||
if (m_WorstValueValid) {
|
||||
m_GoodInThePast = m_GoodInThePast && (m_WorstValue > m_Threshold);
|
||||
m_GoodInThePastValid = true;
|
||||
}
|
||||
if (m_CurrentValueValid) {
|
||||
m_GoodNow = m_GoodNow && (m_CurrentValue > m_Threshold);
|
||||
m_GoodNowValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_Warn = (m_GoodNowValid && !m_GoodNow) || (m_GoodInThePastValid && !m_GoodInThePast);
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::makePretty()
|
||||
{
|
||||
if (m_PrettyUnit == SMART_ATTRIBUTE_UNIT_UNKNOWN)
|
||||
return;
|
||||
|
||||
switch (id()) {
|
||||
case 3:
|
||||
m_PrettyValue = raw() & 0xFFFF;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
m_PrettyValue = raw() & 0xFFFFFFFFU;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
m_PrettyValue = (raw() & 0xFFFFFFFFU) * 60 * 60 * 1000;
|
||||
break;
|
||||
|
||||
case 170:
|
||||
m_PrettyValue = currentValue();
|
||||
break;
|
||||
|
||||
case 190:
|
||||
m_PrettyValue = (raw() & 0xFFFF) * 1000 + 273150;
|
||||
break;
|
||||
|
||||
case 194:
|
||||
m_PrettyValue = (raw() & 0xFFFF) * 1000 + 273150;
|
||||
break;
|
||||
|
||||
case 197:
|
||||
m_PrettyValue = (raw() & 0xFFFFFFFFU);
|
||||
break;
|
||||
|
||||
case 222:
|
||||
m_PrettyValue = (raw() & 0xFFFFFFFFU) * 60 * 60 * 1000;
|
||||
break;
|
||||
|
||||
case 228:
|
||||
m_PrettyValue = raw() * 60 * 1000;
|
||||
break;
|
||||
|
||||
case 231:
|
||||
m_PrettyValue = (raw() & 0xFFFF) * 1000 + 273150;
|
||||
break;
|
||||
|
||||
case 232:
|
||||
m_PrettyValue = currentValue();
|
||||
break;
|
||||
|
||||
case 240:
|
||||
m_PrettyValue = (raw() & 0xFFFFFFFFU) * 60 * 60 * 1000;
|
||||
break;
|
||||
|
||||
case 241:
|
||||
m_PrettyValue = raw() * 65536ULL * 512ULL / 1000000ULL;
|
||||
break;
|
||||
|
||||
case 242:
|
||||
m_PrettyValue = raw() * 65536ULL * 512ULL / 1000000ULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
m_PrettyValue = raw();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::verifyAttribute()
|
||||
{
|
||||
if (id() == 3 || id() == 226)
|
||||
verifyShortTime();
|
||||
else if (id() == 5 || id() == 187 || id() == 197 || id() == 198)
|
||||
verifySectors();
|
||||
else if (id() == 9 || id() == 222 || id() == 240)
|
||||
verifyLongTime();
|
||||
else if (id() == 190 || id() == 194 || id() == 231)
|
||||
verifyTemperature();
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::verifyTemperature()
|
||||
{
|
||||
if (prettyUnit() != SMART_ATTRIBUTE_UNIT_MKELVIN)
|
||||
return;
|
||||
|
||||
if (prettyValue() < MKELVIN_VALID_MIN || prettyValue() > MKELVIN_VALID_MAX)
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::verifyShortTime()
|
||||
{
|
||||
if (prettyUnit() != SMART_ATTRIBUTE_UNIT_MSECONDS)
|
||||
return;
|
||||
|
||||
if (prettyValue() < MSECOND_VALID_MIN || prettyValue() > MSECOND_VALID_SHORT_MAX)
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::verifyLongTime()
|
||||
{
|
||||
if (prettyUnit() != SMART_ATTRIBUTE_UNIT_MSECONDS)
|
||||
return;
|
||||
|
||||
if (prettyValue() < MSECOND_VALID_MIN || prettyValue() > MSECOND_VALID_LONG_MAX)
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
}
|
||||
|
||||
void SmartAttributeParsedData::verifySectors()
|
||||
{
|
||||
if (prettyUnit() != SMART_ATTRIBUTE_UNIT_SECTORS)
|
||||
return;
|
||||
|
||||
quint64 maxSectors = disk()->size() / 512ULL;
|
||||
|
||||
if (prettyValue() == 0xFFFFFFFFULL || prettyValue() == 0xFFFFFFFFFFFFULL || (maxSectors > 0
|
||||
&& prettyValue() > maxSectors))
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
else if ((id() == 5 || id() == 197) && prettyValue() > 0)
|
||||
m_Warn = true;
|
||||
}
|
||||
|
||||
bool SmartAttributeParsedData::updateUnit()
|
||||
{
|
||||
if (m_Quirk) {
|
||||
switch (id()) {
|
||||
case 3:
|
||||
if (m_Quirk & SMART_QUIRK_3_UNUSED) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (m_Quirk & SMART_QUIRK_4_UNUSED) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_UNKNOWN;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (m_Quirk & SMART_QUIRK_5_UNKNOWN)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
if (m_Quirk & SMART_QUIRK_9_POWERONMINUTES) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_MSECONDS;
|
||||
return true;
|
||||
} else if (m_Quirk & SMART_QUIRK_9_POWERONSECONDS) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_MSECONDS;
|
||||
return true;
|
||||
} else if (m_Quirk & SMART_QUIRK_9_POWERONHALFMINUTES) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_MSECONDS;
|
||||
return true;
|
||||
} else if (m_Quirk & SMART_QUIRK_9_UNKNOWN)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 190:
|
||||
if (m_Quirk & SMART_QUIRK_190_UNKNOWN)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 192:
|
||||
if (m_Quirk & SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_NONE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 194:
|
||||
if (m_Quirk & SMART_QUIRK_194_10XCELSIUS) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_MKELVIN;
|
||||
return true;
|
||||
} else if (m_Quirk & SMART_QUIRK_194_UNKNOWN)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 197:
|
||||
if (m_Quirk & SMART_QUIRK_197_UNKNOWN)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 198:
|
||||
if (m_Quirk & SMART_QUIRK_198_UNKNOWN)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 200:
|
||||
if (m_Quirk & SMART_QUIRK_200_WRITEERRORCOUNT) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_NONE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 201:
|
||||
if (m_Quirk & SMART_QUIRK_201_DETECTEDTACOUNT) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_NONE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 225:
|
||||
if (m_Quirk & SMART_QUIRK_225_TOTALLBASWRITTEN) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_MB;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 226:
|
||||
if (m_Quirk & SMART_QUIRK_226_TIMEWORKLOADMEDIAWEAR) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_SMALL_PERCENT;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 227:
|
||||
if (m_Quirk & SMART_QUIRK_227_TIMEWORKLOADHOSTREADS) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_SMALL_PERCENT;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 228:
|
||||
if (m_Quirk & SMART_QUIRK_228_WORKLOADTIMER) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_MSECONDS;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 232:
|
||||
if (m_Quirk & SMART_QUIRK_232_AVAILABLERESERVEDSPACE) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_PERCENT;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 233:
|
||||
if (m_Quirk & SMART_QUIRK_233_MEDIAWEAROUTINDICATOR) {
|
||||
m_PrettyUnit = SMART_ATTRIBUTE_UNIT_PERCENT;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (tableUnit().contains(id())) {
|
||||
m_PrettyUnit = tableUnit()[id()];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const QMap<qint32, SmartAttributeParsedData::SmartAttributeUnit> tableUnit()
|
||||
{
|
||||
QMap<qint32, SmartAttributeParsedData::SmartAttributeUnit> table;
|
||||
table.insert(1, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(2, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(3, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS);
|
||||
table.insert(4, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(5, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_SECTORS);
|
||||
table.insert(6, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(7, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(8, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(9, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS);
|
||||
table.insert(10, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(11, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(12, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(13, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(170, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_PERCENT);
|
||||
table.insert(171, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(172, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(175, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(176, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(177, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(178, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(179, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(180, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(181, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(182, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(183, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(184, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(187, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_SECTORS);
|
||||
table.insert(188, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(189, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(190, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN);
|
||||
table.insert(191, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(192, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(193, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(194, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN);
|
||||
table.insert(195, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(196, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(197, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_SECTORS);
|
||||
table.insert(198, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_SECTORS);
|
||||
table.insert(199, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(200, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(201, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(202, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(203, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(204, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(205, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(206, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(207, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(208, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(209, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(220, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(221, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(222, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS);
|
||||
table.insert(223, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(224, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(225, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(226, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS);
|
||||
table.insert(227, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(228, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
table.insert(230, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(231, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN);
|
||||
table.insert(232, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_PERCENT);
|
||||
table.insert(233, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(234, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_SECTORS);
|
||||
table.insert(235, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_UNKNOWN);
|
||||
table.insert(240, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS);
|
||||
table.insert(241, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MB);
|
||||
table.insert(242, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MB);
|
||||
table.insert(250, SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static const SmartAttributeParsedData::SmartQuirkDataBase *quirkDatabase()
|
||||
{
|
||||
static const SmartAttributeParsedData::SmartQuirkDataBase quirkDb[] = {
|
||||
{
|
||||
"^(FUJITSU MHY2120BH|FUJITSU MHY2250BH)$",
|
||||
"^0085000B$",
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_9_POWERONMINUTES |
|
||||
SmartAttributeParsedData::SMART_QUIRK_197_UNKNOWN |
|
||||
SmartAttributeParsedData::SMART_QUIRK_198_UNKNOWN)
|
||||
},
|
||||
{
|
||||
"^FUJITSU MHR2040AT$",
|
||||
NULL,
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_9_POWERONSECONDS |
|
||||
SmartAttributeParsedData::SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT |
|
||||
SmartAttributeParsedData::SMART_QUIRK_200_WRITEERRORCOUNT)
|
||||
},
|
||||
{
|
||||
"^FUJITSU MHS20[6432]0AT( .)?$",
|
||||
NULL,
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_9_POWERONSECONDS |
|
||||
SmartAttributeParsedData::SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT |
|
||||
SmartAttributeParsedData::SMART_QUIRK_200_WRITEERRORCOUNT |
|
||||
SmartAttributeParsedData::SMART_QUIRK_201_DETECTEDTACOUNT)
|
||||
},
|
||||
{
|
||||
"^("
|
||||
"FUJITSU M1623TAU|"
|
||||
"FUJITSU MHG2...ATU?.*|"
|
||||
"FUJITSU MHH2...ATU?.*|"
|
||||
"FUJITSU MHJ2...ATU?.*|"
|
||||
"FUJITSU MHK2...ATU?.*|"
|
||||
"FUJITSU MHL2300AT|"
|
||||
"FUJITSU MHM2(20|15|10|06)0AT|"
|
||||
"FUJITSU MHN2...AT|"
|
||||
"FUJITSU MHR2020AT|"
|
||||
"FUJITSU MHT2...(AH|AS|AT|BH)U?.*|"
|
||||
"FUJITSU MHU2...ATU?.*|"
|
||||
"FUJITSU MHV2...(AH|AS|AT|BH|BS|BT).*|"
|
||||
"FUJITSU MP[A-G]3...A[HTEV]U?.*"
|
||||
")$",
|
||||
NULL,
|
||||
SmartAttributeParsedData::SMART_QUIRK_9_POWERONSECONDS
|
||||
},
|
||||
{
|
||||
"^("
|
||||
"SAMSUNG SV4012H|"
|
||||
"SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]"
|
||||
")$",
|
||||
NULL,
|
||||
SmartAttributeParsedData::SMART_QUIRK_9_POWERONHALFMINUTES
|
||||
},
|
||||
{
|
||||
"^("
|
||||
"SAMSUNG SV0412H|"
|
||||
"SAMSUNG SV1204H"
|
||||
")$",
|
||||
NULL,
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_9_POWERONHALFMINUTES |
|
||||
SmartAttributeParsedData::SMART_QUIRK_194_10XCELSIUS)
|
||||
},
|
||||
{
|
||||
"^SAMSUNG SP40A2H$",
|
||||
"^RR100-07$",
|
||||
SmartAttributeParsedData::SMART_QUIRK_9_POWERONHALFMINUTES
|
||||
},
|
||||
{
|
||||
"^SAMSUNG SP80A4H$",
|
||||
"^RT100-06$",
|
||||
SmartAttributeParsedData::SMART_QUIRK_9_POWERONHALFMINUTES
|
||||
},
|
||||
{
|
||||
"^SAMSUNG SP8004H$",
|
||||
"^QW100-61$",
|
||||
SmartAttributeParsedData::SMART_QUIRK_9_POWERONHALFMINUTES
|
||||
},
|
||||
{
|
||||
"^("
|
||||
"Maxtor 2B0(0[468]|1[05]|20)H1|"
|
||||
"Maxtor 4G(120J6|160J[68])|"
|
||||
"Maxtor 4D0(20H1|40H2|60H3|80H4)"
|
||||
")$",
|
||||
NULL,
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_9_POWERONMINUTES |
|
||||
SmartAttributeParsedData::SMART_QUIRK_194_UNKNOWN)
|
||||
},
|
||||
{
|
||||
"^("
|
||||
"Maxtor 2F0[234]0[JL]0|"
|
||||
"Maxtor 8(1280A2|2160A4|2560A4|3840A6|4000A6|5120A8)|"
|
||||
"Maxtor 8(2160D2|3228D3|3240D3|4320D4|6480D6|8400D8|8455D8)|"
|
||||
"Maxtor 9(0510D4|0576D4|0648D5|0720D5|0840D6|0845D6|0864D6|1008D7|1080D8|1152D8)|"
|
||||
"Maxtor 9(1(360|350|202)D8|1190D7|10[12]0D6|0840D5|06[48]0D4|0510D3|1(350|202)E8|1010E6|0840E5|0640E4)|"
|
||||
"Maxtor 9(0512D2|0680D3|0750D3|0913D4|1024D4|1360D6|1536D6|1792D7|2048D8)|"
|
||||
"Maxtor 9(2732U8|2390U7|204[09]U6|1707U5|1366U4|1024U3|0845U3|0683U2)|"
|
||||
"Maxtor 4(R0[68]0[JL]0|R1[26]0L0|A160J0|R120L4)|"
|
||||
"Maxtor (91728D8|91512D7|91303D6|91080D5|90845D4|90645D3|90648D[34]|90432D2)|"
|
||||
"Maxtor 9(0431U1|0641U2|0871U2|1301U3|1741U4)|"
|
||||
"Maxtor (94091U8|93071U6|92561U5|92041U4|91731U4|91531U3|91361U3|91021U2|90841U2|90651U2)|"
|
||||
"Maxtor (33073U4|32049U3|31536U2|30768U1|33073H4|32305H3|31536H2|30768H1)|"
|
||||
"Maxtor (93652U8|92739U6|91826U4|91369U3|90913U2|90845U2|90435U1)|"
|
||||
"Maxtor 9(0684U2|1024U2|1362U3|1536U3|2049U4|2562U5|3073U6|4098U8)|"
|
||||
"Maxtor (54098[UH]8|53073[UH]6|52732[UH]6|52049[UH]4|51536[UH]3|51369[UH]3|51024[UH]2)|"
|
||||
"Maxtor 3(1024H1|1535H2|2049H2|3073H3|4098H4)( B)?|"
|
||||
"Maxtor 5(4610H6|4098H6|3073H4|2049H3|1536H2|1369H2|1023H2)|"
|
||||
"Maxtor 9(1023U2|1536U2|2049U3|2305U3|3073U4|4610U6|6147U8)|"
|
||||
"Maxtor 9(1023H2|1536H2|2049H3|2305H3|3073H4|4098H6|4610H6|6147H8)|"
|
||||
"Maxtor 5T0(60H6|40H4|30H3|20H2|10H1)|"
|
||||
"Maxtor (98196H8|96147H6)|"
|
||||
"Maxtor 4W(100H6|080H6|060H4|040H3|030H2)|"
|
||||
"Maxtor 6(E0[234]|K04)0L0|"
|
||||
"Maxtor 6(B(30|25|20|16|12|10|08)0[MPRS]|L(080[MLP]|(100|120)[MP]|160[MP]|200[MPRS]|250[RS]|300[RS]))0|"
|
||||
"Maxtor 6Y((060|080|120|160)L0|(060|080|120|160|200|250)P0|(060|080|120|160|200|250)M0)|"
|
||||
"Maxtor 7Y250[PM]0|"
|
||||
"Maxtor [45]A(25|30|32)0[JN]0|"
|
||||
"Maxtor 7L(25|30)0[SR]0"
|
||||
")$",
|
||||
NULL,
|
||||
SmartAttributeParsedData::SMART_QUIRK_9_POWERONMINUTES
|
||||
},
|
||||
{
|
||||
"^("
|
||||
"HITACHI_DK14FA-20B|"
|
||||
"HITACHI_DK23..-..B?|"
|
||||
"HITACHI_DK23FA-20J|HTA422020F9AT[JN]0|"
|
||||
"HE[JN]4230[23]0F9AT00|"
|
||||
"HTC4260[23]0G5CE00|HTC4260[56]0G8CE00"
|
||||
")$",
|
||||
NULL,
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_9_POWERONMINUTES |
|
||||
SmartAttributeParsedData::SMART_QUIRK_193_LOADUNLOAD)
|
||||
},
|
||||
{
|
||||
"^HTS541010G9SA00$",
|
||||
"^MBZOC60P$",
|
||||
SmartAttributeParsedData::SMART_QUIRK_5_UNKNOWN
|
||||
},
|
||||
{
|
||||
"^MCCOE64GEMPP$",
|
||||
"^2.9.0[3-9]$",
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_5_UNKNOWN |
|
||||
SmartAttributeParsedData::SMART_QUIRK_190_UNKNOWN)
|
||||
},
|
||||
{
|
||||
"^INTEL SSDSA2(CT|BT|CW|BW)[0-9]{3}G3.*$",
|
||||
NULL,
|
||||
(SmartAttributeParsedData::SmartQuirk) (SmartAttributeParsedData::SMART_QUIRK_3_UNUSED |
|
||||
SmartAttributeParsedData::SMART_QUIRK_4_UNUSED |
|
||||
SmartAttributeParsedData::SMART_QUIRK_225_TOTALLBASWRITTEN |
|
||||
SmartAttributeParsedData::SMART_QUIRK_226_TIMEWORKLOADMEDIAWEAR |
|
||||
SmartAttributeParsedData::SMART_QUIRK_227_TIMEWORKLOADHOSTREADS |
|
||||
SmartAttributeParsedData::SMART_QUIRK_228_WORKLOADTIMER |
|
||||
SmartAttributeParsedData::SMART_QUIRK_232_AVAILABLERESERVEDSPACE |
|
||||
SmartAttributeParsedData::SMART_QUIRK_233_MEDIAWEAROUTINDICATOR)
|
||||
}
|
||||
};
|
||||
|
||||
return quirkDb;
|
||||
}
|
||||
|
||||
static SmartAttributeParsedData::SmartQuirk getQuirk(QString model, QString firmware)
|
||||
{
|
||||
const SmartAttributeParsedData::SmartQuirkDataBase *db;
|
||||
|
||||
QRegularExpression modelRegex;
|
||||
QRegularExpression firmwareRegex;
|
||||
|
||||
for (db = quirkDatabase(); db->model || db->firmware; db++) {
|
||||
if (db->model) {
|
||||
modelRegex.setPattern(QString::fromLocal8Bit(db->model));
|
||||
QRegularExpressionMatch match = modelRegex.match(model);
|
||||
if (!match.hasMatch())
|
||||
continue;
|
||||
}
|
||||
if (db->firmware) {
|
||||
firmwareRegex.setPattern(QString::fromLocal8Bit(db->firmware));
|
||||
QRegularExpressionMatch match = firmwareRegex.match(firmware);
|
||||
if (!match.hasMatch())
|
||||
continue;
|
||||
}
|
||||
return db->quirk;
|
||||
}
|
||||
|
||||
return (SmartAttributeParsedData::SmartQuirk) 0;
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*************************************************************************
|
||||
* Copyright (C) 2018 by Caio Carvalho <caiojcarvalho@gmail.com> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>.*
|
||||
*************************************************************************/
|
||||
|
||||
#if !defined(KPMCORE_SMARTATTRIBUTEPARSEDDATA_H)
|
||||
#define KPMCORE_SMARTATTRIBUTEPARSEDDATA_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
|
||||
class SmartDiskInformation;
|
||||
|
||||
class SmartAttributeParsedData
|
||||
{
|
||||
public:
|
||||
enum SmartAttributeUnit {
|
||||
SMART_ATTRIBUTE_UNIT_UNKNOWN,
|
||||
SMART_ATTRIBUTE_UNIT_NONE,
|
||||
SMART_ATTRIBUTE_UNIT_MSECONDS,
|
||||
SMART_ATTRIBUTE_UNIT_SECTORS,
|
||||
SMART_ATTRIBUTE_UNIT_MKELVIN,
|
||||
SMART_ATTRIBUTE_UNIT_SMALL_PERCENT,
|
||||
SMART_ATTRIBUTE_UNIT_PERCENT,
|
||||
SMART_ATTRIBUTE_UNIT_MB,
|
||||
_SMART_ATTRIBUTE_UNIT_MAX
|
||||
};
|
||||
|
||||
enum SmartQuirk {
|
||||
SMART_QUIRK_9_POWERONMINUTES = 0x000001,
|
||||
SMART_QUIRK_9_POWERONSECONDS = 0x000002,
|
||||
SMART_QUIRK_9_POWERONHALFMINUTES = 0x000004,
|
||||
SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT = 0x000008,
|
||||
SMART_QUIRK_193_LOADUNLOAD = 0x000010,
|
||||
SMART_QUIRK_194_10XCELSIUS = 0x000020,
|
||||
SMART_QUIRK_194_UNKNOWN = 0x000040,
|
||||
SMART_QUIRK_200_WRITEERRORCOUNT = 0x000080,
|
||||
SMART_QUIRK_201_DETECTEDTACOUNT = 0x000100,
|
||||
SMART_QUIRK_5_UNKNOWN = 0x000200,
|
||||
SMART_QUIRK_9_UNKNOWN = 0x000400,
|
||||
SMART_QUIRK_197_UNKNOWN = 0x000800,
|
||||
SMART_QUIRK_198_UNKNOWN = 0x001000,
|
||||
SMART_QUIRK_190_UNKNOWN = 0x002000,
|
||||
SMART_QUIRK_232_AVAILABLERESERVEDSPACE = 0x004000,
|
||||
SMART_QUIRK_233_MEDIAWEAROUTINDICATOR = 0x008000,
|
||||
SMART_QUIRK_225_TOTALLBASWRITTEN = 0x010000,
|
||||
SMART_QUIRK_4_UNUSED = 0x020000,
|
||||
SMART_QUIRK_226_TIMEWORKLOADMEDIAWEAR = 0x040000,
|
||||
SMART_QUIRK_227_TIMEWORKLOADHOSTREADS = 0x080000,
|
||||
SMART_QUIRK_228_WORKLOADTIMER = 0x100000,
|
||||
SMART_QUIRK_3_UNUSED = 0x200000
|
||||
};
|
||||
|
||||
struct SmartQuirkDataBase {
|
||||
const char *model;
|
||||
const char *firmware;
|
||||
SmartAttributeParsedData::SmartQuirk quirk;
|
||||
};
|
||||
|
||||
public:
|
||||
SmartAttributeParsedData(SmartDiskInformation *disk, QJsonObject jsonAttribute);
|
||||
|
||||
SmartAttributeParsedData(const SmartAttributeParsedData &other);
|
||||
|
||||
public:
|
||||
quint32 id() const
|
||||
{
|
||||
return m_Id;
|
||||
}
|
||||
|
||||
qint32 currentValue() const
|
||||
{
|
||||
return m_CurrentValue;
|
||||
}
|
||||
|
||||
qint32 worstValue() const
|
||||
{
|
||||
return m_WorstValue;
|
||||
}
|
||||
|
||||
qint32 threshold() const
|
||||
{
|
||||
return m_Threshold;
|
||||
}
|
||||
|
||||
bool prefailure() const
|
||||
{
|
||||
return m_Prefailure;
|
||||
}
|
||||
|
||||
bool online() const
|
||||
{
|
||||
return m_Online;
|
||||
}
|
||||
|
||||
quint64 raw() const
|
||||
{
|
||||
return m_Raw;
|
||||
}
|
||||
|
||||
quint64 prettyValue() const
|
||||
{
|
||||
return m_PrettyValue;
|
||||
}
|
||||
|
||||
SmartAttributeUnit prettyUnit() const
|
||||
{
|
||||
return m_PrettyUnit;
|
||||
}
|
||||
|
||||
bool goodNowValid() const
|
||||
{
|
||||
return m_GoodNowValid;
|
||||
}
|
||||
|
||||
bool goodNow() const
|
||||
{
|
||||
return m_GoodNow;
|
||||
}
|
||||
|
||||
bool goodInThePastValid() const
|
||||
{
|
||||
return m_GoodInThePastValid;
|
||||
}
|
||||
|
||||
bool goodInThePast() const
|
||||
{
|
||||
return m_GoodInThePast;
|
||||
}
|
||||
|
||||
bool thresholdValid() const
|
||||
{
|
||||
return m_ThresholdValid;
|
||||
}
|
||||
|
||||
bool currentValueValid() const
|
||||
{
|
||||
return m_CurrentValueValid;
|
||||
}
|
||||
|
||||
bool worstValueValid() const
|
||||
{
|
||||
return m_WorstValueValid;
|
||||
}
|
||||
|
||||
bool warn() const
|
||||
{
|
||||
return m_Warn;
|
||||
}
|
||||
|
||||
SmartDiskInformation *disk() const
|
||||
{
|
||||
return m_Disk;
|
||||
}
|
||||
|
||||
protected:
|
||||
void validateValues();
|
||||
|
||||
bool updateUnit();
|
||||
|
||||
void makePretty();
|
||||
|
||||
void verifyAttribute();
|
||||
|
||||
void verifyTemperature();
|
||||
|
||||
void verifyShortTime();
|
||||
|
||||
void verifyLongTime();
|
||||
|
||||
void verifySectors();
|
||||
|
||||
private:
|
||||
quint32 m_Id;
|
||||
qint32 m_CurrentValue;
|
||||
qint32 m_WorstValue;
|
||||
qint32 m_Threshold;
|
||||
quint64 m_Raw;
|
||||
quint64 m_PrettyValue;
|
||||
bool m_CurrentValueValid;
|
||||
bool m_WorstValueValid;
|
||||
bool m_ThresholdValid;
|
||||
bool m_Prefailure;
|
||||
bool m_Online;
|
||||
bool m_GoodNow;
|
||||
bool m_GoodNowValid;
|
||||
bool m_GoodInThePast;
|
||||
bool m_GoodInThePastValid;
|
||||
bool m_Warn;
|
||||
SmartAttributeUnit m_PrettyUnit;
|
||||
SmartDiskInformation *m_Disk;
|
||||
SmartQuirk m_Quirk;
|
||||
};
|
||||
|
||||
#endif // SMARTATTRIBUTEPARSEDDATA_H
|
|
@ -0,0 +1,194 @@
|
|||
/*************************************************************************
|
||||
* Copyright (C) 2018 by Caio Carvalho <caiojcarvalho@gmail.com> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>.*
|
||||
*************************************************************************/
|
||||
|
||||
#include "core/smartdiskinformation.h"
|
||||
#include "core/smartattributeparseddata.h"
|
||||
|
||||
static quint64 u64log2(quint64 n);
|
||||
|
||||
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::SMART_OVERALL_BAD_STATUS)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void SmartDiskInformation::updateOverall()
|
||||
{
|
||||
if (!smartStatus()) {
|
||||
m_Overall = SMART_OVERALL_BAD_STATUS;
|
||||
return;
|
||||
}
|
||||
|
||||
quint64 sector_threshold = u64log2(size() / 512) * 1024;
|
||||
|
||||
if (badSectors() >= sector_threshold) {
|
||||
m_Overall = SMART_OVERALL_BAD_SECTOR_MANY;
|
||||
return;
|
||||
}
|
||||
|
||||
validateBadAttributes();
|
||||
|
||||
if (m_BadAttributeNow) {
|
||||
m_Overall = SMART_OVERALL_BAD_ATTRIBUTE_NOW;
|
||||
return;
|
||||
}
|
||||
|
||||
if (badSectors() > 0) {
|
||||
m_Overall = SMART_OVERALL_BAD_SECTOR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_BadAttributeInThePast) {
|
||||
m_Overall = SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST;
|
||||
return;
|
||||
}
|
||||
|
||||
m_Overall = SMART_OVERALL_GOOD;
|
||||
|
||||
}
|
||||
|
||||
bool SmartDiskInformation::updateTemperature()
|
||||
{
|
||||
SmartAttributeParsedData *temperatureCelsius;
|
||||
SmartAttributeParsedData *temperatureCelsius2;
|
||||
SmartAttributeParsedData *airflowTemperatureCelsius;
|
||||
|
||||
temperatureCelsius = findAttribute(231);
|
||||
temperatureCelsius2 = findAttribute(194);
|
||||
airflowTemperatureCelsius = findAttribute(190);
|
||||
|
||||
if (temperatureCelsius != nullptr
|
||||
&& temperatureCelsius->prettyUnit() == SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN) {
|
||||
m_Temperature = temperatureCelsius->prettyValue();
|
||||
return true;
|
||||
} else if (temperatureCelsius2 != nullptr
|
||||
&& temperatureCelsius2->prettyUnit() == SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN) {
|
||||
m_Temperature = temperatureCelsius2->prettyValue();
|
||||
return true;
|
||||
} else if (airflowTemperatureCelsius != nullptr
|
||||
&& airflowTemperatureCelsius->prettyUnit() ==
|
||||
SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MKELVIN) {
|
||||
m_Temperature = airflowTemperatureCelsius->prettyValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SmartDiskInformation::updatePowerOn()
|
||||
{
|
||||
SmartAttributeParsedData *powerOnHours;
|
||||
SmartAttributeParsedData *powerOnSeconds;
|
||||
|
||||
powerOnHours = findAttribute(9);
|
||||
powerOnSeconds = findAttribute(233);
|
||||
|
||||
if (powerOnHours != nullptr
|
||||
&& powerOnHours->prettyUnit() == SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS) {
|
||||
m_PoweredOn = powerOnHours->prettyValue();
|
||||
return true;
|
||||
} else if (powerOnSeconds != nullptr
|
||||
&& powerOnSeconds->prettyUnit() == SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_MSECONDS) {
|
||||
m_PoweredOn = powerOnSeconds->prettyValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SmartDiskInformation::updatePowerCycle()
|
||||
{
|
||||
SmartAttributeParsedData *powerCycleCount;
|
||||
|
||||
powerCycleCount = findAttribute(12);
|
||||
|
||||
if (powerCycleCount != nullptr
|
||||
&& powerCycleCount->prettyUnit() == SmartAttributeParsedData::SMART_ATTRIBUTE_UNIT_NONE) {
|
||||
m_PowerCycles = powerCycleCount->prettyValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*************************************************************************
|
||||
* Copyright (C) 2018 by Caio Carvalho <caiojcarvalho@gmail.com> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>.*
|
||||
*************************************************************************/
|
||||
|
||||
#if !defined(KPMCORE_SMARTDISKINFORMATION_H)
|
||||
#define SMARTDISKINFORMATION_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
class SmartAttributeParsedData;
|
||||
|
||||
class SmartDiskInformation
|
||||
{
|
||||
public:
|
||||
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
|
||||
};
|
||||
|
||||
enum SmartOverall {
|
||||
SMART_OVERALL_GOOD,
|
||||
SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST,
|
||||
SMART_OVERALL_BAD_SECTOR,
|
||||
SMART_OVERALL_BAD_ATTRIBUTE_NOW,
|
||||
SMART_OVERALL_BAD_SECTOR_MANY,
|
||||
SMART_OVERALL_BAD_STATUS,
|
||||
_SMART_OVERALL_MAX
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const QString firmware() const
|
||||
{
|
||||
return m_FirmwareVersion;
|
||||
}
|
||||
|
||||
const QString serial() const
|
||||
{
|
||||
return m_SerialNumber;
|
||||
}
|
||||
|
||||
quint64 size() const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
bool smartStatus() const
|
||||
{
|
||||
return m_SmartStatus;
|
||||
}
|
||||
|
||||
SmartSelfTestExecutionStatus selfTestExecutionStatus() const
|
||||
{
|
||||
return m_SelfTestExecutionStatus;
|
||||
}
|
||||
|
||||
SmartOverall overall() const
|
||||
{
|
||||
return m_Overall;
|
||||
}
|
||||
|
||||
quint64 temperature() const
|
||||
{
|
||||
return m_Temperature;
|
||||
}
|
||||
|
||||
quint64 badSectors() const
|
||||
{
|
||||
return m_BadSectors;
|
||||
}
|
||||
|
||||
quint64 poweredOn() const
|
||||
{
|
||||
return m_PoweredOn;
|
||||
}
|
||||
|
||||
quint64 powerCycles() const
|
||||
{
|
||||
return m_PowerCycles;
|
||||
}
|
||||
|
||||
QList<SmartAttributeParsedData> attributes() const
|
||||
{
|
||||
return m_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;
|
||||
SmartOverall m_Overall;
|
||||
QList<SmartAttributeParsedData> m_Attributes;
|
||||
|
||||
};
|
||||
|
||||
#endif // SMARTDISKINFORMATION_H
|
|
@ -0,0 +1,155 @@
|
|||
/*************************************************************************
|
||||
* Copyright (C) 2018 by Caio Carvalho <caiojcarvalho@gmail.com> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>.*
|
||||
*************************************************************************/
|
||||
|
||||
#include "core/smartparser.h"
|
||||
|
||||
#include "core/smartattributeparseddata.h"
|
||||
#include "core/smartdiskinformation.h"
|
||||
|
||||
#include "util/externalcommand.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
|
||||
SmartParser::SmartParser(const QString &device_path) :
|
||||
m_DevicePath(device_path),
|
||||
m_DiskInformation(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SmartParser::init()
|
||||
{
|
||||
loadSmartOutput();
|
||||
|
||||
if (m_SmartOutput.isEmpty())
|
||||
return false;
|
||||
|
||||
QJsonObject smartJson = m_SmartOutput.object();
|
||||
|
||||
QString model_name = QString::fromLocal8Bit("model_name");
|
||||
QString firmware = QString::fromLocal8Bit("firmware_version");
|
||||
QString serial_number = QString::fromLocal8Bit("serial_number");
|
||||
QString device = QString::fromLocal8Bit("device");
|
||||
QString smart_status = QString::fromLocal8Bit("smart_status");
|
||||
QString passed = QString::fromLocal8Bit("passed");
|
||||
QString self_test = QString::fromLocal8Bit("self_test");
|
||||
QString status = QString::fromLocal8Bit("status");
|
||||
QString value = QString::fromLocal8Bit("value");
|
||||
QString user_capacity = QString::fromLocal8Bit("user_capacity");
|
||||
|
||||
if (!smartJson.contains(device)) {
|
||||
qDebug() << "smart disk open failed for " << devicePath() << ": " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!smartJson.contains(smart_status)) {
|
||||
qDebug() << "getting smart status failed for " << devicePath() << ": " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!smartJson.contains(model_name) || !smartJson.contains(firmware)
|
||||
|| !smartJson.contains(serial_number)) {
|
||||
qDebug() << "getting disk identification data failed for " << devicePath() << ": " << strerror(
|
||||
errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_DiskInformation = new SmartDiskInformation();
|
||||
|
||||
QJsonObject smartStatus = smartJson[smart_status].toObject();
|
||||
|
||||
m_DiskInformation->setSmartStatus(smartStatus[passed].toBool());
|
||||
|
||||
m_DiskInformation->setModel(smartJson[model_name].toString());
|
||||
m_DiskInformation->setFirmware(smartJson[firmware].toString());
|
||||
m_DiskInformation->setSerial(smartJson[serial_number].toString());
|
||||
m_DiskInformation->setSize(smartJson[user_capacity].toVariant().toULongLong());
|
||||
|
||||
QJsonObject selfTest = smartJson[self_test].toObject();
|
||||
QJsonObject selfTestStatus = selfTest[status].toObject();
|
||||
|
||||
m_DiskInformation->setSelfTestExecutionStatus((SmartDiskInformation::SmartSelfTestExecutionStatus)
|
||||
selfTestStatus[value].toInt());
|
||||
|
||||
loadAttributes();
|
||||
|
||||
m_DiskInformation->updateBadSectors();
|
||||
|
||||
m_DiskInformation->updateOverall();
|
||||
|
||||
if (!m_DiskInformation->updateTemperature())
|
||||
qDebug() << "getting temp failed for " << devicePath() << ": " << strerror(errno);
|
||||
|
||||
if (!m_DiskInformation->updatePowerOn())
|
||||
qDebug() << "getting powered on time failed for " << devicePath() << ": " << strerror(errno);
|
||||
|
||||
if (!m_DiskInformation->updatePowerCycle())
|
||||
qDebug() << "getting power cycles failed for " << devicePath() << ": " << strerror(errno);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartParser::loadSmartOutput()
|
||||
{
|
||||
if (m_SmartOutput.isEmpty()) {
|
||||
QStringList args;
|
||||
args.append(QString::fromLocal8Bit("--all"));
|
||||
args.append(QString::fromLocal8Bit("-j"));
|
||||
args.append(devicePath());
|
||||
|
||||
ExternalCommand smartctl(QString::fromLocal8Bit("smartctl"), args);
|
||||
|
||||
if (smartctl.run() && smartctl.exitCode() == 0) {
|
||||
QByteArray output = smartctl.rawOutput();
|
||||
|
||||
m_SmartOutput = QJsonDocument::fromJson(output);
|
||||
}
|
||||
else
|
||||
qDebug() << "smartctl initialization failed for " << devicePath() << ": " << strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void SmartParser::loadAttributes()
|
||||
{
|
||||
loadSmartOutput();
|
||||
|
||||
if (m_SmartOutput.isEmpty())
|
||||
return;
|
||||
|
||||
QJsonObject smartJson = m_SmartOutput.object();
|
||||
|
||||
QString ata_smart_attributes = QString::fromLocal8Bit("ata_smart_attributes");
|
||||
QString table = QString::fromLocal8Bit("table");
|
||||
|
||||
QJsonObject ataSmartAttributes = smartJson[ata_smart_attributes].toObject();
|
||||
|
||||
QJsonArray attributeArray = ataSmartAttributes[table].toArray();
|
||||
|
||||
if (!m_DiskInformation) {
|
||||
qDebug() << "error loading smart attributes for " << devicePath() << ": " << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const QJsonValue &value : qAsConst(attributeArray)) {
|
||||
SmartAttributeParsedData parsedObject(m_DiskInformation, value.toObject());
|
||||
m_DiskInformation->addAttribute(parsedObject);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*************************************************************************
|
||||
* Copyright (C) 2018 by Caio Carvalho <caiojcarvalho@gmail.com> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>.*
|
||||
*************************************************************************/
|
||||
|
||||
#if !defined(KPMCORE_SMARTPARSER_H)
|
||||
#define KPMCORE_SMARTPARSER_H
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QString>
|
||||
|
||||
class SmartDiskInformation;
|
||||
|
||||
class SmartParser
|
||||
{
|
||||
public:
|
||||
SmartParser(const QString &device_path);
|
||||
|
||||
public:
|
||||
bool init();
|
||||
|
||||
public:
|
||||
const QString &devicePath() const
|
||||
{
|
||||
return m_DevicePath;
|
||||
}
|
||||
|
||||
SmartDiskInformation *diskInformation() const
|
||||
{
|
||||
return m_DiskInformation;
|
||||
}
|
||||
|
||||
protected:
|
||||
void loadSmartOutput();
|
||||
|
||||
void loadAttributes();
|
||||
|
||||
private:
|
||||
const QString m_DevicePath;
|
||||
QJsonDocument m_SmartOutput;
|
||||
SmartDiskInformation *m_DiskInformation;
|
||||
|
||||
};
|
||||
|
||||
#endif // SMARTPARSER_H
|
|
@ -18,13 +18,16 @@
|
|||
|
||||
#include "core/smartstatus.h"
|
||||
|
||||
#include "core/smartparser.h"
|
||||
#include "core/smartdiskinformation.h"
|
||||
#include "core/smartattributeparseddata.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include <atasmart.h>
|
||||
#include <errno.h>
|
||||
|
||||
SmartStatus::SmartStatus(const QString &device_path) :
|
||||
|
@ -46,148 +49,110 @@ SmartStatus::SmartStatus(const QString& device_path) :
|
|||
|
||||
void SmartStatus::update()
|
||||
{
|
||||
SkDisk* skDisk = nullptr;
|
||||
SkBool skSmartStatus = false;
|
||||
uint64_t mkelvin = 0;
|
||||
uint64_t skBadSectors = 0;
|
||||
uint64_t skPoweredOn = 0;
|
||||
uint64_t skPowerCycles = 0;
|
||||
SmartParser parser(devicePath());
|
||||
|
||||
if (sk_disk_open(devicePath().toLocal8Bit().constData(), &skDisk) < 0) {
|
||||
qDebug() << "smart disk open failed for " << devicePath() << ": " << strerror(errno);
|
||||
if (!parser.init()) {
|
||||
qDebug() << "error during smart output parsing for " << devicePath() << ": " << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sk_disk_smart_status(skDisk, &skSmartStatus) < 0) {
|
||||
qDebug() << "getting smart status failed for " << devicePath() << ": " << strerror(errno);
|
||||
sk_disk_free(skDisk);
|
||||
SmartDiskInformation *disk;
|
||||
|
||||
disk = parser.diskInformation();
|
||||
|
||||
if (!disk)
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(skSmartStatus);
|
||||
setStatus(disk->smartStatus());
|
||||
|
||||
if (sk_disk_smart_read_data(skDisk) < 0) {
|
||||
qDebug() << "reading smart data failed for " << devicePath() << ": " << strerror(errno);
|
||||
sk_disk_free(skDisk);
|
||||
return;
|
||||
}
|
||||
setModelName(disk->model());
|
||||
|
||||
const SkIdentifyParsedData* skIdentify;
|
||||
setFirmware(disk->firmware());
|
||||
|
||||
if (sk_disk_identify_parse(skDisk, &skIdentify) < 0)
|
||||
qDebug() << "getting identify data failed for " << devicePath() << ": " << strerror(errno);
|
||||
else {
|
||||
setModelName(QString::fromLocal8Bit(skIdentify->model));
|
||||
setFirmware(QString::fromLocal8Bit(skIdentify->firmware));
|
||||
setSerial(QString::fromLocal8Bit(skIdentify->serial));
|
||||
}
|
||||
setSerial(disk->serial());
|
||||
|
||||
const SkSmartParsedData* skParsed;
|
||||
if (sk_disk_smart_parse(skDisk, &skParsed) < 0)
|
||||
qDebug() << "parsing disk smart data failed for " << devicePath() << ": " << strerror(errno);
|
||||
else {
|
||||
switch (skParsed->self_test_execution_status) {
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
|
||||
switch (disk->selfTestExecutionStatus()) {
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
|
||||
setSelfTestStatus(Aborted);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
|
||||
setSelfTestStatus(Interrupted);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
|
||||
setSelfTestStatus(Fatal);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
|
||||
setSelfTestStatus(ErrorUnknown);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
|
||||
setSelfTestStatus(ErrorEletrical);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
|
||||
setSelfTestStatus(ErrorServo);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
|
||||
setSelfTestStatus(ErrorRead);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
|
||||
setSelfTestStatus(ErrorHandling);
|
||||
break;
|
||||
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
|
||||
setSelfTestStatus(InProgress);
|
||||
break;
|
||||
|
||||
default:
|
||||
case SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
|
||||
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
|
||||
setSelfTestStatus(Success);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SkSmartOverall overall;
|
||||
|
||||
if (sk_disk_smart_get_overall(skDisk, &overall) < 0)
|
||||
qDebug() << "getting status failed for " << devicePath() << ": " << strerror(errno);
|
||||
else {
|
||||
switch (overall) {
|
||||
case SK_SMART_OVERALL_GOOD:
|
||||
switch (disk->overall()) {
|
||||
case SmartDiskInformation::SMART_OVERALL_GOOD:
|
||||
setOverall(Good);
|
||||
break;
|
||||
|
||||
case SK_SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST:
|
||||
case SmartDiskInformation::SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST:
|
||||
setOverall(BadPast);
|
||||
break;
|
||||
|
||||
case SK_SMART_OVERALL_BAD_SECTOR:
|
||||
case SmartDiskInformation::SMART_OVERALL_BAD_SECTOR:
|
||||
setOverall(BadSectors);
|
||||
break;
|
||||
|
||||
case SK_SMART_OVERALL_BAD_ATTRIBUTE_NOW:
|
||||
case SmartDiskInformation::SMART_OVERALL_BAD_ATTRIBUTE_NOW:
|
||||
setOverall(BadNow);
|
||||
break;
|
||||
|
||||
case SK_SMART_OVERALL_BAD_SECTOR_MANY:
|
||||
case SmartDiskInformation::SMART_OVERALL_BAD_SECTOR_MANY:
|
||||
setOverall(BadSectorsMany);
|
||||
break;
|
||||
|
||||
default:
|
||||
case SK_SMART_OVERALL_BAD_STATUS:
|
||||
case SmartDiskInformation::SMART_OVERALL_BAD_STATUS:
|
||||
setOverall(Bad);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sk_disk_smart_get_temperature(skDisk, &mkelvin) < 0)
|
||||
qDebug() << "getting temp failed for " << devicePath() << ": " << strerror(errno);
|
||||
else
|
||||
setTemp(mkelvin);
|
||||
setTemp(disk->temperature());
|
||||
|
||||
if (sk_disk_smart_get_bad(skDisk, &skBadSectors) < 0)
|
||||
qDebug() << "getting bad sectors failed for " << devicePath() << ": " << strerror(errno);
|
||||
else
|
||||
setBadSectors(skBadSectors);
|
||||
setBadSectors(disk->badSectors());
|
||||
|
||||
if (sk_disk_smart_get_power_on(skDisk, &skPoweredOn) < 0)
|
||||
qDebug() << "getting powered on time failed for " << devicePath() << ": " << strerror(errno);
|
||||
else
|
||||
setPoweredOn(skPoweredOn);
|
||||
setPoweredOn(disk->poweredOn());
|
||||
|
||||
if (sk_disk_smart_get_power_cycle(skDisk, &skPowerCycles) < 0)
|
||||
qDebug() << "getting power cycles failed for " << devicePath() << ": " << strerror(errno);
|
||||
else
|
||||
setPowerCycles(skPowerCycles);
|
||||
setPowerCycles(disk->powerCycles());
|
||||
|
||||
m_Attributes.clear();
|
||||
addAttributes(disk->attributes());
|
||||
|
||||
sk_disk_smart_parse_attributes(skDisk, callback, this);
|
||||
|
||||
sk_disk_free(skDisk);
|
||||
setInitSuccess(true);
|
||||
}
|
||||
|
||||
|
@ -195,7 +160,8 @@ 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));
|
||||
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)
|
||||
|
@ -260,11 +226,13 @@ QString SmartStatus::overallAssessmentToString(Overall o)
|
|||
|
||||
}
|
||||
|
||||
void SmartStatus::callback(SkDisk*, const SkSmartAttributeParsedData* a, void* user_data)
|
||||
void SmartStatus::addAttributes(QList<SmartAttributeParsedData> attr)
|
||||
{
|
||||
SmartStatus* self = reinterpret_cast<SmartStatus*>(user_data);
|
||||
m_Attributes.clear();
|
||||
|
||||
SmartAttribute sm(a);
|
||||
self->m_Attributes.append(sm);
|
||||
for (const SmartAttributeParsedData &at : qAsConst(attr)) {
|
||||
SmartAttribute sm(at);
|
||||
m_Attributes.append(sm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,87 +63,111 @@ public:
|
|||
public:
|
||||
void update();
|
||||
|
||||
const QString& devicePath() const {
|
||||
const QString &devicePath() const
|
||||
{
|
||||
return m_DevicePath;
|
||||
}
|
||||
bool isValid() const {
|
||||
bool isValid() const
|
||||
{
|
||||
return m_InitSuccess;
|
||||
}
|
||||
bool status() const {
|
||||
bool status() const
|
||||
{
|
||||
return m_Status;
|
||||
}
|
||||
const QString& modelName() const {
|
||||
const QString &modelName() const
|
||||
{
|
||||
return m_ModelName;
|
||||
}
|
||||
const QString& serial() const {
|
||||
const QString &serial() const
|
||||
{
|
||||
return m_Serial;
|
||||
}
|
||||
const QString& firmware() const {
|
||||
const QString &firmware() const
|
||||
{
|
||||
return m_Firmware;
|
||||
}
|
||||
quint64 temp() const {
|
||||
quint64 temp() const
|
||||
{
|
||||
return m_Temp;
|
||||
}
|
||||
quint64 badSectors() const {
|
||||
quint64 badSectors() const
|
||||
{
|
||||
return m_BadSectors;
|
||||
}
|
||||
quint64 powerCycles() const {
|
||||
quint64 powerCycles() const
|
||||
{
|
||||
return m_PowerCycles;
|
||||
}
|
||||
quint64 poweredOn() const {
|
||||
quint64 poweredOn() const
|
||||
{
|
||||
return m_PoweredOn;
|
||||
}
|
||||
const Attributes& attributes() const {
|
||||
const Attributes &attributes() const
|
||||
{
|
||||
return m_Attributes;
|
||||
}
|
||||
Overall overall() const {
|
||||
Overall overall() const
|
||||
{
|
||||
return m_Overall;
|
||||
}
|
||||
SelfTestStatus selfTestStatus() const {
|
||||
SelfTestStatus selfTestStatus() const
|
||||
{
|
||||
return m_SelfTestStatus;
|
||||
}
|
||||
|
||||
void addAttributes(QList<SmartAttributeParsedData> attr);
|
||||
|
||||
static QString tempToString(quint64 mkelvin);
|
||||
static QString overallAssessmentToString(Overall o);
|
||||
static QString selfTestStatusToString(SmartStatus::SelfTestStatus s);
|
||||
|
||||
protected:
|
||||
void setStatus(bool s) {
|
||||
void setStatus(bool s)
|
||||
{
|
||||
m_Status = s;
|
||||
}
|
||||
void setModelName(const QString& name) {
|
||||
void setModelName(const QString &name)
|
||||
{
|
||||
m_ModelName = name;
|
||||
}
|
||||
void setSerial(const QString& s) {
|
||||
void setSerial(const QString &s)
|
||||
{
|
||||
m_Serial = s;
|
||||
}
|
||||
void setFirmware(const QString& f) {
|
||||
void setFirmware(const QString &f)
|
||||
{
|
||||
m_Firmware = f;
|
||||
}
|
||||
void setTemp(quint64 t) {
|
||||
void setTemp(quint64 t)
|
||||
{
|
||||
m_Temp = t;
|
||||
}
|
||||
void setInitSuccess(bool b) {
|
||||
void setInitSuccess(bool b)
|
||||
{
|
||||
m_InitSuccess = b;
|
||||
}
|
||||
void setBadSectors(quint64 s) {
|
||||
void setBadSectors(quint64 s)
|
||||
{
|
||||
m_BadSectors = s;
|
||||
}
|
||||
void setPowerCycles(quint64 p) {
|
||||
void setPowerCycles(quint64 p)
|
||||
{
|
||||
m_PowerCycles = p;
|
||||
}
|
||||
void setPoweredOn(quint64 t) {
|
||||
void setPoweredOn(quint64 t)
|
||||
{
|
||||
m_PoweredOn = t;
|
||||
}
|
||||
void setOverall(Overall o) {
|
||||
void setOverall(Overall o)
|
||||
{
|
||||
m_Overall = o;
|
||||
}
|
||||
void setSelfTestStatus(SelfTestStatus s) {
|
||||
void setSelfTestStatus(SelfTestStatus s)
|
||||
{
|
||||
m_SelfTestStatus = s;
|
||||
}
|
||||
|
||||
static void callback(SkDisk* skDisk, const SkSmartAttributeParsedData* a, void* user_data);
|
||||
|
||||
private:
|
||||
const QString m_DevicePath;
|
||||
bool m_InitSuccess;
|
||||
|
|
|
@ -126,6 +126,7 @@ bool luks::create(Report& report, const QString& deviceNode)
|
|||
QStringLiteral("512"),
|
||||
QStringLiteral("--batch-mode"),
|
||||
QStringLiteral("--force-password"),
|
||||
QStringLiteral("--type"), QStringLiteral("luks1"),
|
||||
QStringLiteral("luksFormat"),
|
||||
deviceNode });
|
||||
if (!( createCmd.write(m_passphrase.toLocal8Bit() + '\n') &&
|
||||
|
@ -143,6 +144,7 @@ bool luks::create(Report& report, const QString& deviceNode)
|
|||
if (!( openCmd.write(m_passphrase.toLocal8Bit() + '\n') && openCmd.start(-1) && openCmd.waitFor()))
|
||||
return false;
|
||||
|
||||
setPayloadSize();
|
||||
scan(deviceNode);
|
||||
|
||||
if (mapperName().isEmpty())
|
||||
|
@ -259,6 +261,7 @@ bool luks::cryptOpen(QWidget* parent, const QString& deviceNode)
|
|||
QString passphrase = dlg.password();
|
||||
ExternalCommand openCmd(QStringLiteral("cryptsetup"),
|
||||
{ QStringLiteral("open"),
|
||||
QStringLiteral("--tries"), QStringLiteral("1"),
|
||||
deviceNode,
|
||||
suggestedMapperName(deviceNode) });
|
||||
|
||||
|
@ -490,19 +493,18 @@ bool luks::resize(Report& report, const QString& deviceNode, qint64 newLength) c
|
|||
if (mapperName().isEmpty())
|
||||
return false;
|
||||
|
||||
qint64 payloadLength = newLength - payloadOffset();
|
||||
if ( newLength - length() * sectorSize() > 0 )
|
||||
{
|
||||
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() });
|
||||
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
|
||||
|
||||
if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0)
|
||||
return m_innerFs->resize(report, mapperName(), payloadLength);
|
||||
return m_innerFs->resize(report, mapperName(), m_PayloadSize);
|
||||
}
|
||||
else if (m_innerFs->resize(report, mapperName(), payloadLength))
|
||||
else if (m_innerFs->resize(report, mapperName(), m_PayloadSize))
|
||||
{
|
||||
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"),
|
||||
{ QStringLiteral("--size"), QString::number(payloadLength / 512), // LUKS payload length is specified in multiples of 512 bytes
|
||||
{ QStringLiteral("--size"), QString::number(m_PayloadSize / 512), // LUKS1 payload length is specified in multiples of 512 bytes
|
||||
QStringLiteral("resize"), mapperName() });
|
||||
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
|
||||
if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0)
|
||||
|
@ -589,8 +591,7 @@ void luks::getMapperName(const QString& deviceNode)
|
|||
|
||||
void luks::getLuksInfo(const QString& deviceNode)
|
||||
{
|
||||
ExternalCommand cmd(QStringLiteral("cryptsetup"),
|
||||
{ QStringLiteral("luksDump"), deviceNode });
|
||||
ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("luksDump"), deviceNode });
|
||||
if (cmd.run(-1) && cmd.exitCode() == 0) {
|
||||
QRegularExpression re(QStringLiteral("Cipher name:\\s+(\\w+)"));
|
||||
QRegularExpressionMatch rem = re.match(cmd.output());
|
||||
|
@ -667,6 +668,7 @@ bool luks::canEncryptType(FileSystem::Type type)
|
|||
|
||||
void luks::initLUKS()
|
||||
{
|
||||
setPayloadSize();
|
||||
QString mapperNode = mapperName();
|
||||
bool isCryptOpen = !mapperNode.isEmpty();
|
||||
setCryptOpen(isCryptOpen);
|
||||
|
@ -676,4 +678,22 @@ void luks::initLUKS()
|
|||
}
|
||||
}
|
||||
|
||||
void luks::setPayloadSize()
|
||||
{
|
||||
ExternalCommand dmsetupCmd(QStringLiteral("dmsetup"), { QStringLiteral("table"), mapperName() });
|
||||
dmsetupCmd.run();
|
||||
QRegularExpression re(QStringLiteral("\\d+ (\\d+)"));
|
||||
QRegularExpressionMatch rem = re.match(dmsetupCmd.output());
|
||||
if (rem.hasMatch())
|
||||
m_PayloadSize = rem.captured(1).toLongLong() * sectorSize();
|
||||
}
|
||||
|
||||
bool luks::testPassphrase(const QString& deviceNode, const QString& passphrase) const {
|
||||
ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("open"), QStringLiteral("--tries"), QStringLiteral("1"), QStringLiteral("--test-passphrase"), deviceNode });
|
||||
if (cmd.start(-1) && cmd.write(passphrase.toLocal8Bit() + '\n') == passphrase.toLocal8Bit().length() + 1 && cmd.waitFor() && cmd.exitCode() == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,12 @@ public:
|
|||
luks(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, FileSystem::Type t = FileSystem::Luks);
|
||||
~luks() override;
|
||||
|
||||
enum KeyLocation {
|
||||
unknown,
|
||||
dmcrypt,
|
||||
keyring
|
||||
};
|
||||
|
||||
public:
|
||||
void init() override;
|
||||
void scan(const QString& deviceNode) override;
|
||||
|
@ -167,9 +173,9 @@ public:
|
|||
QString suggestedMapperName(const QString& deviceNode) const;
|
||||
|
||||
void getMapperName(const QString& deviceNode);
|
||||
void getLuksInfo(const QString& deviceNode);
|
||||
virtual void getLuksInfo(const QString& deviceNode);
|
||||
|
||||
FileSystem* innerFS() const { return m_innerFs; } // avoid calling this unless necessary
|
||||
FileSystem* innerFS() const { return m_innerFs; }
|
||||
QString outerUuid() const;
|
||||
|
||||
QString mapperName() const { return m_MapperName; }
|
||||
|
@ -182,8 +188,11 @@ public:
|
|||
static bool canEncryptType(FileSystem::Type type);
|
||||
void initLUKS();
|
||||
|
||||
bool testPassphrase(const QString& deviceNode, const QString& passphrase) const;
|
||||
|
||||
protected:
|
||||
virtual QString readOuterUUID(const QString& deviceNode) const;
|
||||
void setPayloadSize();
|
||||
|
||||
public:
|
||||
static CommandSupportType m_GetUsed;
|
||||
|
@ -213,7 +222,10 @@ protected:
|
|||
QString m_HashName;
|
||||
qint64 m_KeySize;
|
||||
qint64 m_PayloadOffset;
|
||||
qint64 m_PayloadSize;
|
||||
QString m_outerUuid;
|
||||
|
||||
luks::KeyLocation m_KeyLocation = unknown;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
107
src/fs/luks2.cpp
107
src/fs/luks2.cpp
|
@ -17,6 +17,13 @@
|
|||
|
||||
#include "fs/luks2.h"
|
||||
|
||||
#include "util/externalcommand.h"
|
||||
#include "util/report.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
namespace FS
|
||||
{
|
||||
|
||||
|
@ -36,4 +43,104 @@ FileSystem::Type luks2::type() const
|
|||
return FileSystem::Luks2;
|
||||
}
|
||||
|
||||
bool luks2::create(Report& report, const QString& deviceNode)
|
||||
{
|
||||
Q_ASSERT(m_innerFs);
|
||||
Q_ASSERT(!m_passphrase.isEmpty());
|
||||
|
||||
ExternalCommand createCmd(report, QStringLiteral("cryptsetup"),
|
||||
{ QStringLiteral("-s"),
|
||||
QStringLiteral("512"),
|
||||
QStringLiteral("--batch-mode"),
|
||||
QStringLiteral("--force-password"),
|
||||
QStringLiteral("--type"), QStringLiteral("luks2"),
|
||||
QStringLiteral("luksFormat"),
|
||||
deviceNode });
|
||||
if (!( createCmd.start(-1) &&
|
||||
createCmd.write(m_passphrase.toLocal8Bit() + '\n') == m_passphrase.toLocal8Bit().length() + 1 &&
|
||||
createCmd.waitFor() && createCmd.exitCode() == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ExternalCommand openCmd(report, QStringLiteral("cryptsetup"),
|
||||
{ QStringLiteral("open"),
|
||||
deviceNode,
|
||||
suggestedMapperName(deviceNode) });
|
||||
|
||||
if (!( openCmd.start(-1) && openCmd.write(m_passphrase.toLocal8Bit() + '\n') == m_passphrase.toLocal8Bit().length() + 1 && openCmd.waitFor()))
|
||||
return false;
|
||||
|
||||
setPayloadSize();
|
||||
scan(deviceNode);
|
||||
|
||||
if (mapperName().isEmpty())
|
||||
return false;
|
||||
|
||||
if (!m_innerFs->create(report, mapperName()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool luks2::resize(Report& report, const QString& deviceNode, qint64 newLength) const
|
||||
{
|
||||
Q_ASSERT(m_innerFs);
|
||||
|
||||
if (mapperName().isEmpty())
|
||||
return false;
|
||||
|
||||
if ( newLength - length() * sectorSize() > 0 )
|
||||
{
|
||||
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() });
|
||||
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
|
||||
|
||||
cryptResizeCmd.start(-1);
|
||||
if (m_KeyLocation == keyring) {
|
||||
if (m_passphrase.isEmpty())
|
||||
return false;
|
||||
cryptResizeCmd.write(m_passphrase.toLocal8Bit() + '\n');
|
||||
}
|
||||
cryptResizeCmd.waitFor();
|
||||
if ( cryptResizeCmd.exitCode() == 0 )
|
||||
return m_innerFs->resize(report, mapperName(), m_PayloadSize);
|
||||
}
|
||||
else if (m_innerFs->resize(report, mapperName(), m_PayloadSize))
|
||||
{
|
||||
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"),
|
||||
{ QStringLiteral("--size"), QString::number(m_PayloadSize / 512), // FIXME, LUKS2 can have different sector sizes
|
||||
QStringLiteral("resize"), mapperName() });
|
||||
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
|
||||
cryptResizeCmd.start(-1);
|
||||
if (m_KeyLocation == keyring) {
|
||||
if (m_passphrase.isEmpty())
|
||||
return false;
|
||||
cryptResizeCmd.write(m_passphrase.toLocal8Bit() + '\n');
|
||||
}
|
||||
cryptResizeCmd.waitFor();
|
||||
if ( cryptResizeCmd.exitCode() == 0 )
|
||||
return true;
|
||||
}
|
||||
report.line() << xi18nc("@info:progress", "Resizing encrypted file system on partition <filename>%1</filename> failed.", deviceNode);
|
||||
return false;
|
||||
}
|
||||
|
||||
luks::KeyLocation luks2::keyLocation()
|
||||
{
|
||||
m_KeyLocation = unknown;
|
||||
ExternalCommand statusCmd(QStringLiteral("cryptsetup"), { QStringLiteral("status"), mapperName() });
|
||||
if (statusCmd.run(-1) && statusCmd.exitCode() == 0) {
|
||||
QRegularExpression re(QStringLiteral("key location:\\s+(\\w+)"));
|
||||
QRegularExpressionMatch rem = re.match(statusCmd.output());
|
||||
if (rem.hasMatch()) {
|
||||
if (rem.captured(1) == QStringLiteral("keyring"))
|
||||
m_KeyLocation = keyring;
|
||||
else if (rem.captured(1) == QStringLiteral("dm-crypt"))
|
||||
m_KeyLocation = dmcrypt;
|
||||
}
|
||||
}
|
||||
|
||||
return m_KeyLocation;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,7 +38,12 @@ public:
|
|||
luks2(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label);
|
||||
~luks2() override;
|
||||
|
||||
bool create(Report& report, const QString& deviceNode) override;
|
||||
bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
|
||||
|
||||
FileSystem::Type type() const override;
|
||||
|
||||
luks::KeyLocation keyLocation();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,12 @@
|
|||
|
||||
namespace FS
|
||||
{
|
||||
constexpr qint64 MIN_UDF_BLOCKS = 282;
|
||||
constexpr qint64 MIN_UDF_BLOCKS = 300;
|
||||
constexpr qint64 MAX_UDF_BLOCKS = ((1ULL << 32) - 1);
|
||||
|
||||
FileSystem::CommandSupportType udf::m_GetUsed = FileSystem::cmdSupportNone;
|
||||
FileSystem::CommandSupportType udf::m_SetLabel = FileSystem::cmdSupportNone;
|
||||
FileSystem::CommandSupportType udf::m_UpdateUUID = FileSystem::cmdSupportNone;
|
||||
FileSystem::CommandSupportType udf::m_Create = FileSystem::cmdSupportNone;
|
||||
bool udf::oldMkudffsVersion = false;
|
||||
|
||||
|
@ -43,6 +46,8 @@ udf::udf(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QStrin
|
|||
|
||||
void udf::init()
|
||||
{
|
||||
m_GetUsed = findExternal(QStringLiteral("udfinfo"), {}, 1) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_SetLabel = m_UpdateUUID = findExternal(QStringLiteral("udflabel"), {}, 1) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_Create = findExternal(QStringLiteral("mkudffs"), {}, 1) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
|
||||
if (m_Create == cmdSupportFileSystem) {
|
||||
|
@ -55,7 +60,11 @@ void udf::init()
|
|||
|
||||
bool udf::supportToolFound() const
|
||||
{
|
||||
return m_Create != cmdSupportNone;
|
||||
return
|
||||
m_GetUsed != cmdSupportNone &&
|
||||
m_SetLabel != cmdSupportNone &&
|
||||
m_UpdateUUID != cmdSupportNone &&
|
||||
m_Create != cmdSupportNone;
|
||||
}
|
||||
|
||||
FileSystem::SupportTool udf::supportToolName() const
|
||||
|
@ -94,6 +103,36 @@ QValidator* udf::labelValidator(QObject *parent) const
|
|||
return m_LabelValidator;
|
||||
}
|
||||
|
||||
qint64 udf::readUsedCapacity(const QString& deviceNode) const
|
||||
{
|
||||
ExternalCommand cmd(QStringLiteral("udfinfo"), { QStringLiteral("--utf8"), deviceNode });
|
||||
if (!cmd.run(-1) || cmd.exitCode() != 0)
|
||||
return -1;
|
||||
|
||||
QRegularExpressionMatch reBlockSize = QRegularExpression(QStringLiteral("^blocksize=([0-9]+)$"), QRegularExpression::MultilineOption).match(cmd.output());
|
||||
QRegularExpressionMatch reUsedBlocks = QRegularExpression(QStringLiteral("^usedblocks=([0-9]+)$"), QRegularExpression::MultilineOption).match(cmd.output());
|
||||
|
||||
if (!reBlockSize.hasMatch() || !reUsedBlocks.hasMatch())
|
||||
return -1;
|
||||
|
||||
qint64 blockSize = reBlockSize.captured(1).toLongLong();
|
||||
qint64 usedBlocks = reUsedBlocks.captured(1).toLongLong();
|
||||
|
||||
return usedBlocks * blockSize;
|
||||
}
|
||||
|
||||
bool udf::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel)
|
||||
{
|
||||
ExternalCommand cmd(report, QStringLiteral("udflabel"), { QStringLiteral("--utf8"), deviceNode, newLabel });
|
||||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
bool udf::updateUUID(Report& report, const QString& deviceNode) const
|
||||
{
|
||||
ExternalCommand cmd(report, QStringLiteral("udflabel"), { QStringLiteral("--utf8"), QStringLiteral("--uuid=random"), deviceNode });
|
||||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
bool udf::create(Report& report, const QString& deviceNode)
|
||||
{
|
||||
return createWithLabel(report, deviceNode, QString());
|
||||
|
|
15
src/fs/udf.h
15
src/fs/udf.h
|
@ -42,9 +42,15 @@ public:
|
|||
public:
|
||||
void init() override;
|
||||
|
||||
qint64 readUsedCapacity(const QString& deviceNode) const override;
|
||||
bool create(Report& report, const QString& deviceNode) override;
|
||||
bool createWithLabel(Report& report, const QString& deviceNode, const QString& label) override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
}
|
||||
CommandSupportType supportGetLabel() const override {
|
||||
return cmdSupportCore;
|
||||
}
|
||||
|
@ -63,6 +69,12 @@ public:
|
|||
CommandSupportType supportBackup() const override {
|
||||
return cmdSupportCore;
|
||||
}
|
||||
CommandSupportType supportSetLabel() const override {
|
||||
return m_SetLabel;
|
||||
}
|
||||
CommandSupportType supportUpdateUUID() const override {
|
||||
return m_UpdateUUID;
|
||||
}
|
||||
CommandSupportType supportGetUUID() const override {
|
||||
return cmdSupportCore;
|
||||
}
|
||||
|
@ -75,6 +87,9 @@ public:
|
|||
bool supportToolFound() const override;
|
||||
|
||||
public:
|
||||
static CommandSupportType m_GetUsed;
|
||||
static CommandSupportType m_SetLabel;
|
||||
static CommandSupportType m_UpdateUUID;
|
||||
static CommandSupportType m_Create;
|
||||
|
||||
private:
|
||||
|
|
|
@ -73,7 +73,6 @@ bool SetPartGeometryJob::run(Report& parent)
|
|||
delete backendPartitionTable;
|
||||
}
|
||||
|
||||
|
||||
delete backendDevice;
|
||||
} else
|
||||
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> while trying to resize/move partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
|
||||
|
|
|
@ -1,7 +1,35 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=KDE Partition Manager sfdisk Backend
|
||||
Name[ca]=Dorsal «sfdisk» del gestor de particions del KDE
|
||||
Name[ca@valencia]=Dorsal «sfdisk» del gestor de particions del KDE
|
||||
Name[de]=KDE-Partitionsverwaltung sfdisk-Backend
|
||||
Name[gl]=Infraestrutura de sfdisk do xestor de particións de KDE
|
||||
Name[nl]=Sfdisk-backend van KDE-partitiebeheerder
|
||||
Name[pl]=Silnik sfdisk zarządzania partycjami KDE
|
||||
Name[pt]=Infra-Estrutura do 'sfdisk' do Gestor de Partições do KDE
|
||||
Name[sr]=Позадина sfdisk‑а за КДЕ‑ов менаџер партиција
|
||||
Name[sr@ijekavian]=Позадина sfdisk‑а за КДЕ‑ов менаџер партиција
|
||||
Name[sr@ijekavianlatin]=Pozadina sfdisk‑a za KDE‑ov menadžer particija
|
||||
Name[sr@latin]=Pozadina sfdisk‑a za KDE‑ov menadžer particija
|
||||
Name[sv]=KDE:s partitionshanterare sfdisk bakgrundsprogram
|
||||
Name[uk]=Додаток sfdisk сервера Керування розділами KDE
|
||||
Name[x-test]=xxKDE Partition Manager sfdisk Backendxx
|
||||
Comment=A KDE Partition Manager sfdisk backend.
|
||||
Comment[ca]=Un dorsal «sfdisk» del gestor de particions del KDE.
|
||||
Comment[ca@valencia]=Un dorsal «sfdisk» del gestor de particions del KDE.
|
||||
Comment[de]=Ein sfdisk-Backend für die KDE-Partitionsverwaltung.
|
||||
Comment[gl]=Unha infraestrutura de sfdisk do xestor de particións de KDE.
|
||||
Comment[nl]=Sfdisk-backend van KDE-partitiebeheerder
|
||||
Comment[pl]=Silnik sfdisk zarządzania partycjami KDE.
|
||||
Comment[pt]=A infra-estrutura do 'sfdisk' do Gestor de Partições do KDE.
|
||||
Comment[sr]=Позадина sfdisk‑а за КДЕ‑ов менаџер партиција
|
||||
Comment[sr@ijekavian]=Позадина sfdisk‑а за КДЕ‑ов менаџер партиција
|
||||
Comment[sr@ijekavianlatin]=Pozadina sfdisk‑a za KDE‑ov menadžer particija
|
||||
Comment[sr@latin]=Pozadina sfdisk‑a za KDE‑ov menadžer particija
|
||||
Comment[sv]=KDE:s partitionshanterare sfdisk bakgrundsprogram
|
||||
Comment[uk]=Додаток sfdisk сервера Керування розділами KDE.
|
||||
Comment[x-test]=xxA KDE Partition Manager sfdisk backend.xx
|
||||
Type=Service
|
||||
ServiceTypes=PartitionManager/Plugin
|
||||
Icon=preferences-plugin
|
||||
|
|
Loading…
Reference in New Issue