Warning, file /system/kpmcore/src/core/smartparser.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com> 0003 SPDX-FileCopyrightText: 2020 Andrius Štikonas <andrius@stikonas.eu> 0004 0005 SPDX-License-Identifier: GPL-3.0-or-later 0006 */ 0007 0008 #include "core/smartparser.h" 0009 0010 #include "core/smartattributeparseddata.h" 0011 #include "core/smartdiskinformation.h" 0012 0013 #include "util/externalcommand.h" 0014 0015 #include <errno.h> 0016 #include <utility> 0017 0018 #include <QDebug> 0019 #include <QJsonArray> 0020 #include <QJsonDocument> 0021 #include <QJsonObject> 0022 #include <QString> 0023 0024 /** Creates a new SmartParser object 0025 @param device_path device path that indicates the device that SMART must analyze 0026 */ 0027 SmartParser::SmartParser(const QString &device_path) : 0028 m_DevicePath(device_path), 0029 m_DiskInformation(nullptr) 0030 { 0031 } 0032 0033 SmartParser::~SmartParser() 0034 { 0035 delete m_DiskInformation; 0036 } 0037 0038 /** Initialize SmartParser data, retrieve the information from SMART JSON and initialize the disk information data */ 0039 bool SmartParser::init() 0040 { 0041 loadSmartOutput(); 0042 0043 if (m_SmartOutput.isEmpty()) 0044 return false; 0045 0046 QJsonObject smartJson = m_SmartOutput.object(); 0047 0048 QString model_name = QStringLiteral("model_name"); 0049 QString firmware = QStringLiteral("firmware_version"); 0050 QString serial_number = QStringLiteral("serial_number"); 0051 QString device = QStringLiteral("device"); 0052 QString smart_status = QStringLiteral("smart_status"); 0053 QString passed = QStringLiteral("passed"); 0054 QString self_test = QStringLiteral("self_test"); 0055 QString status = QStringLiteral("status"); 0056 QString value = QStringLiteral("value"); 0057 QString user_capacity = QStringLiteral("user_capacity"); 0058 QString blocks = QStringLiteral("blocks"); 0059 0060 if (!smartJson.contains(device)) { 0061 qDebug() << "smart disk open failed for " << devicePath() << ": " << strerror(errno); 0062 return false; 0063 } 0064 0065 if (!smartJson.contains(smart_status)) { 0066 qDebug() << "getting smart status failed for " << devicePath() << ": " << strerror(errno); 0067 return false; 0068 } 0069 0070 if (!smartJson.contains(model_name) || !smartJson.contains(firmware) 0071 || !smartJson.contains(serial_number)) { 0072 qDebug() << "getting disk identification data failed for " << devicePath() << ": " << strerror( 0073 errno); 0074 return false; 0075 } 0076 0077 m_DiskInformation = new SmartDiskInformation(); 0078 0079 QJsonObject smartStatus = smartJson[smart_status].toObject(); 0080 0081 m_DiskInformation->setSmartStatus(smartStatus[passed].toBool()); 0082 0083 m_DiskInformation->setModel(smartJson[model_name].toString()); 0084 m_DiskInformation->setFirmware(smartJson[firmware].toString()); 0085 m_DiskInformation->setSerial(smartJson[serial_number].toString()); 0086 0087 const auto user_capacity_object = smartJson[user_capacity].toObject(); 0088 QString user_capacity_blocks = QStringLiteral("bytes"); 0089 m_DiskInformation->setSectors(user_capacity_object[user_capacity_blocks].toVariant().toULongLong()); 0090 0091 QJsonObject selfTest = smartJson[self_test].toObject(); 0092 QJsonObject selfTestStatus = selfTest[status].toObject(); 0093 0094 m_DiskInformation->setSelfTestExecutionStatus(static_cast<SmartStatus::SelfTestStatus>(selfTestStatus[value].toInt())); 0095 0096 loadAttributes(); 0097 0098 m_DiskInformation->updateBadSectors(); 0099 0100 m_DiskInformation->updateOverall(); 0101 0102 if (!m_DiskInformation->updateTemperature()) 0103 qDebug() << "getting temp failed for " << devicePath() << ": " << strerror(errno); 0104 0105 if (!m_DiskInformation->updatePowerOn()) 0106 qDebug() << "getting powered on time failed for " << devicePath() << ": " << strerror(errno); 0107 0108 if (!m_DiskInformation->updatePowerCycle()) 0109 qDebug() << "getting power cycles failed for " << devicePath() << ": " << strerror(errno); 0110 0111 return true; 0112 } 0113 0114 /** Run smartctl command and recover its output */ 0115 void SmartParser::loadSmartOutput() 0116 { 0117 if (m_SmartOutput.isEmpty()) { 0118 ExternalCommand smartctl(QStringLiteral("smartctl"), { QStringLiteral("--all"), QStringLiteral("--json"), devicePath() }); 0119 0120 // Exit status of smartctl is a bitfield, check that bits 0 and 1 are not set: 0121 // - bit 0: command line did not parse; 0122 // - bit 1: device open failed. 0123 // See `man 8 smartctl` for more details. 0124 if (smartctl.run() && (smartctl.exitCode() & 1) == 0 && (smartctl.exitCode() & 2) == 0) { 0125 QByteArray output = smartctl.rawOutput(); 0126 0127 m_SmartOutput = QJsonDocument::fromJson(output); 0128 } 0129 else 0130 qDebug() << "smartctl initialization failed for " << devicePath() << ": " << strerror(errno); 0131 } 0132 } 0133 0134 /** Load SMART disk attributes from JSON data */ 0135 void SmartParser::loadAttributes() 0136 { 0137 loadSmartOutput(); 0138 0139 if (m_SmartOutput.isEmpty()) 0140 return; 0141 0142 QJsonObject smartJson = m_SmartOutput.object(); 0143 0144 QString ata_smart_attributes = QStringLiteral("ata_smart_attributes"); 0145 QString table = QStringLiteral("table"); 0146 0147 QJsonObject ataSmartAttributes = smartJson[ata_smart_attributes].toObject(); 0148 0149 QJsonArray attributeArray = ataSmartAttributes[table].toArray(); 0150 0151 if (!m_DiskInformation) { 0152 qDebug() << "error loading smart attributes for " << devicePath() << ": " << strerror(errno); 0153 return; 0154 } 0155 0156 for (const QJsonValue &value : std::as_const(attributeArray)) { 0157 SmartAttributeParsedData parsedObject(m_DiskInformation, value.toObject()); 0158 m_DiskInformation->addAttribute(parsedObject); 0159 } 0160 }