File indexing completed on 2024-04-14 05:26:59

0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0002 // SPDX-FileCopyrightText: 2020-2021 Harald Sitter <sitter@kde.org>
0003 
0004 #include "smartdata.h"
0005 
0006 #include <QJsonDocument>
0007 #include <QJsonObject>
0008 #include <QJsonValue>
0009 
0010 #include "kded_debug.h"
0011 
0012 SMARTStatus::SMARTStatus(const QJsonObject &object)
0013     : m_passed(object[QStringLiteral("passed")].toBool())
0014 {
0015     // Should we decide to map the value. Its meaning is "defined" in
0016     // nvmeprint.cpp of smartmontools
0017 }
0018 SMARTCtlData::SMARTCtlData(const QJsonObject &object)
0019     : m_exitStatus(object[QStringLiteral("exit_status")].toInt(static_cast<int>(SMART::Failure::None)))
0020 {
0021 }
0022 
0023 SMART::Failures SMARTCtlData::failure() const
0024 {
0025     return {static_cast<SMART::Failure>(m_exitStatus)};
0026 }
0027 
0028 SMARTData::SMARTData(const QJsonDocument &document)
0029     : m_smartctl(SMARTCtlData(document.object()[QStringLiteral("smartctl")].toObject()))
0030     , m_status(SMARTStatus(document.object()[QStringLiteral("smart_status")].toObject()))
0031     , m_device(document.object()[QStringLiteral("device")].toObject()[QStringLiteral("name")].toString())
0032     , m_valid(checkValid(document))
0033 {
0034 }
0035 
0036 bool SMARTData::checkValid(const QJsonDocument &document) const
0037 {
0038     if (m_smartctl.failure() & SMART::Failure::CmdLineParse) {
0039         qCDebug(KDED) << "Command line error" << m_device << document.toJson();
0040         return false;
0041     }
0042     if (m_smartctl.failure() & SMART::Failure::DeviceOpen) {
0043         qCDebug(KDED) << "Failed to open device" << m_device << document.toJson();
0044         return false;
0045     }
0046     const bool hasSMARTStatus = document.object().contains(QStringLiteral("smart_status"));
0047     const bool internalCommandFailure = (m_smartctl.failure() & SMART::Failure::InternalCommand);
0048     if (!hasSMARTStatus && internalCommandFailure) {
0049         // VirtualBox drives return with InternalCommand problems and no SMART data. Consider the data invalid.
0050         // If we also have other failure codes we'll still want to consider the data valid as it might indicate
0051         // problems.
0052         qCDebug(KDED) << "Internal command problems resulted in no smart_status data" << m_device << document.toJson();
0053         return false;
0054     }
0055     const bool noFailure = m_smartctl.failure() == SMART::Failures();
0056     if (!hasSMARTStatus && noFailure) {
0057         // When SMART is disabled we may get a blob back but it will lack any information on the SMART status.
0058         // Unfortunately the fact that SMART was disabled (versus not available etc.) isn't codified in the JSON.
0059         // https://bugs.kde.org/show_bug.cgi?id=435699
0060         qCDebug(KDED) << "SMART support is either disabled or not supported on the device" << m_device << document.toJson();
0061         return false;
0062     }
0063 
0064     return true;
0065 }