Merge branch 'smart' into kauth

This commit is contained in:
Andrius Štikonas 2018-01-11 11:31:18 +01:00
commit 790553aa0b
21 changed files with 1888 additions and 210 deletions

View File

@ -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/)

View File

@ -7,7 +7,5 @@ set(BACKEND_SRC
set(BACKEND_LIB_HDRS
backend/corebackend.h
backend/corebackenddevice.h
backend/corebackendmanager.h
backend/corebackendpartitiontable.h
)

View File

@ -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
)

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

155
src/core/smartparser.cpp Normal file
View File

@ -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);
}
}

57
src/core/smartparser.h Normal file
View File

@ -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

View File

@ -18,16 +18,19 @@
#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) :
SmartStatus::SmartStatus(const QString &device_path) :
m_DevicePath(device_path),
m_InitSuccess(false),
m_Status(false),
@ -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(disk->smartStatus());
setModelName(disk->model());
setFirmware(disk->firmware());
setSerial(disk->serial());
switch (disk->selfTestExecutionStatus()) {
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
setSelfTestStatus(Aborted);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
setSelfTestStatus(Interrupted);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
setSelfTestStatus(Fatal);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
setSelfTestStatus(ErrorUnknown);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
setSelfTestStatus(ErrorEletrical);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
setSelfTestStatus(ErrorServo);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
setSelfTestStatus(ErrorRead);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
setSelfTestStatus(ErrorHandling);
break;
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
setSelfTestStatus(InProgress);
break;
default:
case SmartDiskInformation::SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
setSelfTestStatus(Success);
break;
}
setStatus(skSmartStatus);
switch (disk->overall()) {
case SmartDiskInformation::SMART_OVERALL_GOOD:
setOverall(Good);
break;
case SmartDiskInformation::SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST:
setOverall(BadPast);
break;
case SmartDiskInformation::SMART_OVERALL_BAD_SECTOR:
setOverall(BadSectors);
break;
case SmartDiskInformation::SMART_OVERALL_BAD_ATTRIBUTE_NOW:
setOverall(BadNow);
break;
case SmartDiskInformation::SMART_OVERALL_BAD_SECTOR_MANY:
setOverall(BadSectorsMany);
break;
default:
case SmartDiskInformation::SMART_OVERALL_BAD_STATUS:
setOverall(Bad);
break;
if (sk_disk_smart_read_data(skDisk) < 0) {
qDebug() << "reading smart data failed for " << devicePath() << ": " << strerror(errno);
sk_disk_free(skDisk);
return;
}
const SkIdentifyParsedData* skIdentify;
setTemp(disk->temperature());
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));
}
setBadSectors(disk->badSectors());
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:
setSelfTestStatus(Aborted);
break;
setPoweredOn(disk->poweredOn());
case SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
setSelfTestStatus(Interrupted);
break;
setPowerCycles(disk->powerCycles());
case SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
setSelfTestStatus(Fatal);
break;
addAttributes(disk->attributes());
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
setSelfTestStatus(ErrorUnknown);
break;
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
setSelfTestStatus(ErrorEletrical);
break;
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
setSelfTestStatus(ErrorServo);
break;
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
setSelfTestStatus(ErrorRead);
break;
case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
setSelfTestStatus(ErrorHandling);
break;
case SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
setSelfTestStatus(InProgress);
break;
default:
case SK_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:
setOverall(Good);
break;
case SK_SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST:
setOverall(BadPast);
break;
case SK_SMART_OVERALL_BAD_SECTOR:
setOverall(BadSectors);
break;
case SK_SMART_OVERALL_BAD_ATTRIBUTE_NOW:
setOverall(BadNow);
break;
case SK_SMART_OVERALL_BAD_SECTOR_MANY:
setOverall(BadSectorsMany);
break;
default:
case SK_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);
if (sk_disk_smart_get_bad(skDisk, &skBadSectors) < 0)
qDebug() << "getting bad sectors failed for " << devicePath() << ": " << strerror(errno);
else
setBadSectors(skBadSectors);
if (sk_disk_smart_get_power_on(skDisk, &skPoweredOn) < 0)
qDebug() << "getting powered on time failed for " << devicePath() << ": " << strerror(errno);
else
setPoweredOn(skPoweredOn);
if (sk_disk_smart_get_power_cycle(skDisk, &skPowerCycles) < 0)
qDebug() << "getting power cycles failed for " << devicePath() << ": " << strerror(errno);
else
setPowerCycles(skPowerCycles);
m_Attributes.clear();
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);
}
}

View File

@ -58,92 +58,116 @@ public:
typedef QList<SmartAttribute> Attributes;
public:
SmartStatus(const QString& device_path);
SmartStatus(const QString &device_path);
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;

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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;
}
}

View File

@ -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();
};
}

View File

@ -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());

View File

@ -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:

View File

@ -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());

View File

@ -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 sfdiska za KDEov menadžer particija
Name[sr@latin]=Pozadina sfdiska za KDEov 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 sfdiska za KDEov menadžer particija
Comment[sr@latin]=Pozadina sfdiska za KDEov 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