Refactored storage property classes (better naming, documentation), removed app_gtkmm_features.h.

This commit is contained in:
Alexander Shaduri
2021-03-16 16:06:28 +04:00
parent d74da816a1
commit 788a4760b8
27 changed files with 1288 additions and 1229 deletions
+9 -10
View File
@@ -10,10 +10,13 @@ target_sources(applib PRIVATE
async_command_executor.cpp
async_command_executor.h
app_builder_widget.h
app_gtkmm_features.h
app_gtkmm_utils.cpp
app_gtkmm_utils.h
app_gtkmm_tools.cpp
app_gtkmm_tools.h
app_pcrecpp.h
ata_storage_property.cpp
ata_storage_property.h
ata_storage_property_descr.cpp
ata_storage_property_descr.h
command_executor.h
command_executor.cpp
command_executor_3ware.h
@@ -29,8 +32,8 @@ target_sources(applib PRIVATE
smartctl_executor.cpp
smartctl_executor_gui.h
smartctl_executor.h
smartctl_parser.cpp
smartctl_parser.h
smartctl_text_parser.cpp
smartctl_text_parser.h
storage_detector.cpp
storage_detector.h
storage_detector_helpers.h
@@ -42,12 +45,8 @@ target_sources(applib PRIVATE
storage_detector_win32.h
storage_device.cpp
storage_device.h
storage_property_colors.h
storage_property.cpp
storage_property_descr.cpp
storage_property_descr.h
storage_property.h
storage_settings.h
warning_colors.h
warning_level.h
)
-39
View File
@@ -1,39 +0,0 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup applib
/// \weakgroup applib
/// @{
#ifndef APP_GTKMM_FEATURES_H
#define APP_GTKMM_FEATURES_H
#include "local_glibmm.h"
#include <gtkmm.h>
/// \def APP_GTKMM_CHECK_VERSION(major, minor, micro)
/// Similar to GTK_CHECK_VERSION, but for Gtkmm, which lacks this before gtkmm4.
/// This is useful as Gtk and Gtkmm versions may differ.
#ifndef APP_GTKMM_CHECK_VERSION
#define APP_GTKMM_CHECK_VERSION(major, minor, micro) \
(GTKMM_MAJOR_VERSION > (major) \
|| (GTKMM_MAJOR_VERSION == (major) && (GTKMM_MINOR_VERSION > (minor) \
|| (GTKMM_MINOR_VERSION == (minor) && GTKMM_MICRO_VERSION >= (micro)) \
) \
) \
)
#endif
#endif
/// @}
@@ -15,7 +15,7 @@ Copyright:
#include <cstring> // std::strlen
#include <vector>
#include "app_gtkmm_utils.h"
#include "app_gtkmm_tools.h"
@@ -9,14 +9,30 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef APP_GTKMM_UTILS_H
#define APP_GTKMM_UTILS_H
#ifndef APP_GTKMM_TOOLS_H
#define APP_GTKMM_TOOLS_H
#include <string>
#include <gtkmm.h>
/// \def APP_GTKMM_CHECK_VERSION(major, minor, micro)
/// Similar to GTK_CHECK_VERSION, but for Gtkmm, which lacks this before gtkmm4.
/// This is useful as Gtk and Gtkmm versions may differ.
#ifndef APP_GTKMM_CHECK_VERSION
#define APP_GTKMM_CHECK_VERSION(major, minor, micro) \
(GTKMM_MAJOR_VERSION > (major) \
|| (GTKMM_MAJOR_VERSION == (major) && (GTKMM_MINOR_VERSION > (minor) \
|| (GTKMM_MINOR_VERSION == (minor) && GTKMM_MICRO_VERSION >= (micro)) \
) \
) \
)
#endif
/// Get column header widget of a tree view column.
/// Note: This works only if the column has custom widget set.
/// \return nullptr on failure.
+503
View File
@@ -0,0 +1,503 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup applib
/// \weakgroup applib
/// @{
#include "local_glibmm.h"
#include <map>
#include <ostream> // not iosfwd - it doesn't work
#include <sstream>
#include <iomanip>
#include <locale>
#include "hz/string_num.h" // number_to_string
#include "hz/stream_cast.h" // stream_cast<>
#include "hz/format_unit.h" // format_time_length
#include "hz/string_algo.h" // string_join
#include "hz/string_num.h" // number_to_string
#include "ata_storage_property.h"
std::ostream& operator<< (std::ostream& os, const AtaStorageCapability& p)
{
os
// << p.name << ": "
<< p.flag_value;
for (auto&& v : p.strvalues) {
os << "\n\t" << v;
}
return os;
}
std::string AtaStorageAttribute::get_attr_type_name(AtaStorageAttribute::AttributeType type)
{
static const std::unordered_map<AttributeType, std::string> m {
{AttributeType::unknown, "[unknown]"},
{AttributeType::prefail, "pre-failure"},
{AttributeType::old_age, "old age"},
};
if (auto iter = m.find(type); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
std::string AtaStorageAttribute::get_update_type_name(AtaStorageAttribute::UpdateType type)
{
static const std::unordered_map<UpdateType, std::string> m {
{UpdateType::unknown, "[unknown]"},
{UpdateType::always, "continuously"},
{UpdateType::offline, "on offline data collect."},
};
if (auto iter = m.find(type); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
std::string AtaStorageAttribute::get_fail_time_name(AtaStorageAttribute::FailTime type)
{
static const std::unordered_map<FailTime, std::string> m {
{FailTime::unknown, "[unknown]"},
{FailTime::none, "never"},
{FailTime::past, "in the past"},
{FailTime::now, "now"},
};
if (auto iter = m.find(type); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
std::string AtaStorageAttribute::format_raw_value() const
{
// If it's fully a number, format it with commas
if (hz::number_to_string_nolocale(raw_value_int) == raw_value) {
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << raw_value_int;
return ss.str();
}
return raw_value;
}
std::ostream& operator<< (std::ostream& os, const AtaStorageAttribute& p)
{
// os << p.name << ": "
if (p.value.has_value()) {
os << static_cast<int>(p.value.value());
} else {
os << "-";
}
os << " (" << p.format_raw_value() << ")";
return os;
}
bool AtaStorageStatistic::is_normalized() const
{
return flags.find('N') != std::string::npos;
}
std::string AtaStorageStatistic::format_value() const
{
// If it's fully a number, format it with commas
if (hz::number_to_string_nolocale(value_int) == value) {
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << value_int;
return ss.str();
}
return value;
}
std::ostream& operator<<(std::ostream& os, const AtaStorageStatistic& p)
{
os << p.value;
return os;
}
std::string AtaStorageErrorBlock::get_displayable_error_types(const std::vector<std::string>& types)
{
static const std::map<std::string, std::string> m = {
{"ABRT", _("Command aborted")},
{"AMNF", _("Address mark not found")},
{"CCTO", _("Command completion timed out")},
{"EOM", _("End of media")},
{"ICRC", _("Interface CRC error")},
{"IDNF", _("Identity not found")},
{"ILI", _("(Packet command-set specific)")},
{"MC", _("Media changed")},
{"MCR", _("Media change request")},
{"NM", _("No media")},
{"obs", _("Obsolete")},
{"TK0NF", _("Track 0 not found")},
{"UNC", _("Uncorrectable error in data")},
{"WP", _("Media is write protected")},
};
std::vector<std::string> sv;
for (const auto& type : types) {
if (m.find(type) != m.end()) {
sv.push_back(m.at(type));
} else {
std::string name = _("Uknown type");
if (!type.empty()) {
name = Glib::ustring::compose(_("Uknown type: %1"), type);
}
sv.push_back(name);
}
}
return hz::string_join(sv, _(", "));
}
WarningLevel AtaStorageErrorBlock::get_warning_level_for_error_type(const std::string& type)
{
static const std::map<std::string, WarningLevel> m = {
{"ABRT", WarningLevel::none},
{"AMNF", WarningLevel::alert},
{"CCTO", WarningLevel::warning},
{"EOM", WarningLevel::warning},
{"ICRC", WarningLevel::warning},
{"IDNF", WarningLevel::alert},
{"ILI", WarningLevel::notice},
{"MC", WarningLevel::none},
{"MCR", WarningLevel::none},
{"NM", WarningLevel::none},
{"obs", WarningLevel::none},
{"TK0NF", WarningLevel::alert},
{"UNC", WarningLevel::alert},
{"WP", WarningLevel::none},
};
if (m.find(type) != m.end()) {
return m.at(type);
}
return WarningLevel::none; // unknown error
}
std::string AtaStorageErrorBlock::format_lifetime_hours() const
{
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << lifetime_hours;
return ss.str();
}
std::ostream& operator<< (std::ostream& os, const AtaStorageErrorBlock& b)
{
os << "Error number " << b.error_num << ": "
<< hz::string_join(b.reported_types, ", ")
<< " [" << AtaStorageErrorBlock::get_displayable_error_types(b.reported_types) << "]";
return os;
}
std::string AtaStorageSelftestEntry::get_status_displayable_name(AtaStorageSelftestEntry::Status s)
{
static const std::unordered_map<Status, std::string> m {
{Status::unknown, "[unknown]"},
{Status::completed_no_error, "Completed without error"},
{Status::aborted_by_host, "Manually aborted"},
{Status::interrupted, "Interrupted (host reset)"},
{Status::fatal_or_unknown, "Fatal or unknown error"},
{Status::compl_unknown_failure, "Completed with unknown failure"},
{Status::compl_electrical_failure, "Completed with electrical failure"},
{Status::compl_servo_failure, "Completed with servo/seek failure"},
{Status::compl_read_failure, "Completed with read failure"},
{Status::compl_handling_damage, "Completed: handling damage"},
{Status::in_progress, "In progress"},
{Status::reserved, "Unknown / reserved state"},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
AtaStorageSelftestEntry::StatusSeverity AtaStorageSelftestEntry::get_status_severity(AtaStorageSelftestEntry::Status s)
{
static const std::unordered_map<Status, StatusSeverity> m {
{Status::unknown, StatusSeverity::none},
{Status::completed_no_error, StatusSeverity::none},
{Status::aborted_by_host, StatusSeverity::warning},
{Status::interrupted, StatusSeverity::warning},
{Status::fatal_or_unknown, StatusSeverity::error},
{Status::compl_unknown_failure, StatusSeverity::error},
{Status::compl_electrical_failure, StatusSeverity::error},
{Status::compl_servo_failure, StatusSeverity::error},
{Status::compl_read_failure, StatusSeverity::error},
{Status::compl_handling_damage, StatusSeverity::error},
{Status::in_progress, StatusSeverity::none},
{Status::reserved, StatusSeverity::none},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return StatusSeverity::none;
}
std::string AtaStorageSelftestEntry::get_status_str() const
{
return (status == Status::unknown ? status_str : get_status_displayable_name(status));
}
std::string AtaStorageSelftestEntry::format_lifetime_hours() const
{
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << lifetime_hours;
return ss.str();
}
std::ostream& operator<< (std::ostream& os, const AtaStorageSelftestEntry& b)
{
os << "Test entry " << b.test_num << ": "
<< b.type << ", status: " << b.get_status_str() << ", remaining: " << int(b.remaining_percent);
return os;
}
std::string AtaStorageProperty::get_section_name(AtaStorageProperty::Section s)
{
static const std::unordered_map<Section, std::string> m {
{Section::unknown, "unknown"},
{Section::info, "info"},
{Section::data, "data"},
{Section::internal, "internal"},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
std::string AtaStorageProperty::get_subsection_name(AtaStorageProperty::SubSection s)
{
static const std::unordered_map<SubSection, std::string> m {
{SubSection::unknown, "unknown"},
{SubSection::health, "health"},
{SubSection::capabilities, "capabilities"},
{SubSection::attributes, "attributes"},
{SubSection::devstat, "devstat"},
{SubSection::error_log, "error_log"},
{SubSection::selftest_log, "selftest_log"},
{SubSection::selective_selftest_log, "selective_selftest_log"},
{SubSection::temperature_log, "temperature_log"},
{SubSection::erc_log, "erc_log"},
{SubSection::phy_log, "phy_log"},
{SubSection::directory_log, "directory_log"},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
std::string AtaStorageProperty::get_value_type_name() const
{
if (std::holds_alternative<std::monostate>(value))
return "empty";
if (std::holds_alternative<std::string>(value))
return "string";
if (std::holds_alternative<int64_t>(value))
return "integer";
if (std::holds_alternative<bool>(value))
return "bool";
if (std::holds_alternative<std::chrono::seconds>(value))
return "time_length";
if (std::holds_alternative<AtaStorageCapability>(value))
return "capability";
if (std::holds_alternative<AtaStorageAttribute>(value))
return "attribute";
if (std::holds_alternative<AtaStorageStatistic>(value))
return "statistic";
if (std::holds_alternative<AtaStorageErrorBlock>(value))
return "error_block";
if (std::holds_alternative<AtaStorageSelftestEntry>(value))
return "selftest_entry";
return "[internal_error]";
}
bool AtaStorageProperty::empty() const
{
return std::holds_alternative<std::monostate>(value);
}
void AtaStorageProperty::dump(std::ostream& os, std::size_t internal_offset) const
{
std::string offset(internal_offset, ' ');
os << offset << "[" << get_section_name(section)
<< (section == Section::data ? (", " + get_subsection_name(subsection)) : "") << "]"
<< " " << generic_name
// << (generic_name == reported_name ? "" : (" (" + reported_name + ")"))
<< ": [" << get_value_type_name() << "] ";
// if (!readable_value.empty())
// os << readable_value;
if (std::holds_alternative<std::monostate>(value)) {
os << "[empty]";
} else if (std::holds_alternative<std::string>(value)) {
os << std::get<std::string>(value);
} else if (std::holds_alternative<int64_t>(value)) {
os << std::get<int64_t>(value) << " [" << reported_value << "]";
} else if (std::holds_alternative<bool>(value)) {
os << std::string(std::get<bool>(value) ? "Yes" : "No") << " [" << reported_value << "]";
} else if (std::holds_alternative<std::chrono::seconds>(value)) {
os << std::get<std::chrono::seconds>(value).count() << " sec [" << reported_value << "]";
} else if (std::holds_alternative<AtaStorageCapability>(value)) {
os << std::get<AtaStorageCapability>(value);
} else if (std::holds_alternative<AtaStorageAttribute>(value)) {
os << std::get<AtaStorageAttribute>(value);
} else if (std::holds_alternative<AtaStorageStatistic>(value)) {
os << std::get<AtaStorageStatistic>(value);
} else if (std::holds_alternative<AtaStorageErrorBlock>(value)) {
os << std::get<AtaStorageErrorBlock>(value);
} else if (std::holds_alternative<AtaStorageSelftestEntry>(value)) {
os << std::get<AtaStorageSelftestEntry>(value);
}
}
std::string AtaStorageProperty::format_value(bool add_reported_too) const
{
if (!readable_value.empty())
return readable_value;
if (std::holds_alternative<std::monostate>(value))
return "[unknown]";
if (std::holds_alternative<std::string>(value))
return std::get<std::string>(value);
if (std::holds_alternative<int64_t>(value))
return hz::number_to_string_locale(std::get<int64_t>(value)) + (add_reported_too ? (" [" + reported_value + "]") : "");
if (std::holds_alternative<bool>(value))
return std::string(std::get<bool>(value) ? "Yes" : "No") + (add_reported_too ? (" [" + reported_value + "]") : "");
if (std::holds_alternative<std::chrono::seconds>(value))
return hz::format_time_length(std::get<std::chrono::seconds>(value)) + (add_reported_too ? (" [" + reported_value + "]") : "");
if (std::holds_alternative<AtaStorageCapability>(value))
return hz::stream_cast<std::string>(std::get<AtaStorageCapability>(value));
if (std::holds_alternative<AtaStorageAttribute>(value))
return hz::stream_cast<std::string>(std::get<AtaStorageAttribute>(value));
if (std::holds_alternative<AtaStorageStatistic>(value))
return hz::stream_cast<std::string>(std::get<AtaStorageStatistic>(value));
if (std::holds_alternative<AtaStorageErrorBlock>(value))
return hz::stream_cast<std::string>(std::get<AtaStorageErrorBlock>(value));
if (std::holds_alternative<AtaStorageSelftestEntry>(value))
return hz::stream_cast<std::string>(std::get<AtaStorageSelftestEntry>(value));
return "[internal_error]";
}
std::string AtaStorageProperty::get_description(bool clean) const
{
if (clean)
return this->description;
return (this->description.empty() ? "No description available" : this->description);
}
void AtaStorageProperty::set_description(const std::string& descr)
{
this->description = descr;
}
void AtaStorageProperty::set_name(const std::string& rep_name, const std::string& gen_name, const std::string& read_name)
{
this->reported_name = rep_name;
this->generic_name = (gen_name.empty() ? this->reported_name : gen_name);
this->displayable_name = (read_name.empty() ? this->reported_name : read_name);
}
std::ostream& operator<<(std::ostream& os, const AtaStorageProperty& p)
{
p.dump(os);
return os;
}
/// @}
@@ -9,8 +9,8 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef STORAGE_PROPERTY_H
#define STORAGE_PROPERTY_H
#ifndef ATA_STORAGE_PROPERTY_H
#define ATA_STORAGE_PROPERTY_H
#include <string>
#include <vector>
@@ -27,7 +27,7 @@ Copyright:
/// Holds one block of "capabilities" subsection
/// (only for non-time-interval blocks).
class StorageCapability {
class AtaStorageCapability {
public:
std::string reported_flag_value; ///< original flag value as a string
uint16_t flag_value = 0x0; ///< Flag value. This is one or sometimes two bytes (maybe more?)
@@ -37,14 +37,14 @@ class StorageCapability {
/// Output operator for debug purposes
std::ostream& operator<< (std::ostream& os, const StorageCapability& p);
std::ostream& operator<< (std::ostream& os, const AtaStorageCapability& p);
/// Holds one line of "attributes" subsection
class StorageAttribute {
class AtaStorageAttribute {
public:
/// Disk type the attribute may match
@@ -62,18 +62,7 @@ class StorageAttribute {
};
/// Get readable attribute type name
[[nodiscard]] static std::string get_attr_type_name(AttributeType type)
{
static const std::unordered_map<AttributeType, std::string> m {
{AttributeType::unknown, "[unknown]"},
{AttributeType::prefail, "pre-failure"},
{AttributeType::old_age, "old age"},
};
if (auto iter = m.find(type); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
[[nodiscard]] static std::string get_attr_type_name(AttributeType type);
/// Attribute when-updated type
@@ -84,18 +73,7 @@ class StorageAttribute {
};
/// Get readable when-updated type name
[[nodiscard]] static std::string get_update_type_name(UpdateType type)
{
static const std::unordered_map<UpdateType, std::string> m {
{UpdateType::unknown, "[unknown]"},
{UpdateType::always, "continuously"},
{UpdateType::offline, "on offline data collect."},
};
if (auto iter = m.find(type); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
[[nodiscard]] static std::string get_update_type_name(UpdateType type);
/// Attribute when-failed type
@@ -107,19 +85,7 @@ class StorageAttribute {
};
/// Get a readable when-failed type name
[[nodiscard]] static std::string get_fail_time_name(FailTime type)
{
static const std::unordered_map<FailTime, std::string> m {
{FailTime::unknown, "[unknown]"},
{FailTime::none, "never"},
{FailTime::past, "in the past"},
{FailTime::now, "now"},
};
if (auto iter = m.find(type); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
[[nodiscard]] static std::string get_fail_time_name(FailTime type);
/// Format raw value with commas (if it's a number)
@@ -141,20 +107,17 @@ class StorageAttribute {
/// Output operator for debug purposes
std::ostream& operator<< (std::ostream& os, const StorageAttribute& p);
std::ostream& operator<< (std::ostream& os, const AtaStorageAttribute& p);
/// Holds one line of "devstat" subsection
class StorageStatistic {
class AtaStorageStatistic {
public:
/// Whether the normalization flag is present
[[nodiscard]] bool is_normalized() const
{
return flags.find('N') != std::string::npos;
}
[[nodiscard]] bool is_normalized() const;
/// Format value with commas (if it's a number)
[[nodiscard]] std::string format_value() const;
@@ -169,12 +132,12 @@ class StorageStatistic {
/// Output operator for debug purposes
std::ostream& operator<< (std::ostream& os, const StorageStatistic& p);
std::ostream& operator<< (std::ostream& os, const AtaStorageStatistic& p);
/// Holds one error block of "error log" subsection
class StorageErrorBlock {
class AtaStorageErrorBlock {
public:
/// Get readable error types from reported types
@@ -195,14 +158,14 @@ class StorageErrorBlock {
/// Output operator for debug purposes
std::ostream& operator<< (std::ostream& os, const StorageErrorBlock& b);
std::ostream& operator<< (std::ostream& os, const AtaStorageErrorBlock& b);
/// Holds one entry of selftest_log subsection.
/// Also, holds "Self-test execution status" capability's "internal" section version.
class StorageSelftestEntry {
class AtaStorageSelftestEntry {
public:
/// Self-test log entry status
@@ -229,57 +192,14 @@ class StorageSelftestEntry {
};
/// Get log entry status displayable name
[[nodiscard]] static std::string get_status_displayable_name(Status s)
{
static const std::unordered_map<Status, std::string> m {
{Status::unknown, "[unknown]"},
{Status::completed_no_error, "Completed without error"},
{Status::aborted_by_host, "Manually aborted"},
{Status::interrupted, "Interrupted (host reset)"},
{Status::fatal_or_unknown, "Fatal or unknown error"},
{Status::compl_unknown_failure, "Completed with unknown failure"},
{Status::compl_electrical_failure, "Completed with electrical failure"},
{Status::compl_servo_failure, "Completed with servo/seek failure"},
{Status::compl_read_failure, "Completed with read failure"},
{Status::compl_handling_damage, "Completed: handling damage"},
{Status::in_progress, "In progress"},
{Status::reserved, "Unknown / reserved state"},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
[[nodiscard]] static std::string get_status_displayable_name(Status s);
/// Get severity of error status
[[nodiscard]] static StatusSeverity get_status_severity(Status s)
{
static const std::unordered_map<Status, StatusSeverity> m {
{Status::unknown, StatusSeverity::none},
{Status::completed_no_error, StatusSeverity::none},
{Status::aborted_by_host, StatusSeverity::warning},
{Status::interrupted, StatusSeverity::warning},
{Status::fatal_or_unknown, StatusSeverity::error},
{Status::compl_unknown_failure, StatusSeverity::error},
{Status::compl_electrical_failure, StatusSeverity::error},
{Status::compl_servo_failure, StatusSeverity::error},
{Status::compl_read_failure, StatusSeverity::error},
{Status::compl_handling_damage, StatusSeverity::error},
{Status::in_progress, StatusSeverity::none},
{Status::reserved, StatusSeverity::none},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return StatusSeverity::none;
}
[[nodiscard]] static StatusSeverity get_status_severity(Status s);
/// Get error status as a string
[[nodiscard]] std::string get_status_str() const
{
return (status == Status::unknown ? status_str : get_status_displayable_name(status));
}
[[nodiscard]] std::string get_status_str() const;
/// Format lifetime hours with comma
@@ -297,13 +217,13 @@ class StorageSelftestEntry {
/// Output operator for debug purposes
std::ostream& operator<< (std::ostream& os, const StorageSelftestEntry& b);
std::ostream& operator<< (std::ostream& os, const AtaStorageSelftestEntry& b);
/// A single parser-extracted property
class StorageProperty {
class AtaStorageProperty {
public:
/// Sections in output
@@ -315,19 +235,7 @@ class StorageProperty {
};
/// Get displayable section type name
[[nodiscard]] static std::string get_section_name(Section s)
{
static const std::unordered_map<Section, std::string> m {
{Section::unknown, "unknown"},
{Section::info, "info"},
{Section::data, "data"},
{Section::internal, "internal"},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
[[nodiscard]] static std::string get_section_name(Section s);
/// Subsections in smart data section
@@ -347,61 +255,15 @@ class StorageProperty {
};
/// Get displayable subsection type name
[[nodiscard]] static std::string get_subsection_name(SubSection s)
{
static const std::unordered_map<SubSection, std::string> m {
{SubSection::unknown, "unknown"},
{SubSection::health, "health"},
{SubSection::capabilities, "capabilities"},
{SubSection::attributes, "attributes"},
{SubSection::devstat, "devstat"},
{SubSection::error_log, "error_log"},
{SubSection::selftest_log, "selftest_log"},
{SubSection::selective_selftest_log, "selective_selftest_log"},
{SubSection::temperature_log, "temperature_log"},
{SubSection::erc_log, "erc_log"},
{SubSection::phy_log, "phy_log"},
{SubSection::directory_log, "directory_log"},
};
if (auto iter = m.find(s); iter != m.end()) {
return iter->second;
}
return "[internal_error]";
}
[[nodiscard]] static std::string get_subsection_name(SubSection s);
/// Get displayable value type name
[[nodiscard]] std::string get_value_type_name() const
{
if (std::holds_alternative<std::monostate>(value))
return "empty";
if (std::holds_alternative<std::string>(value))
return "string";
if (std::holds_alternative<int64_t>(value))
return "integer";
if (std::holds_alternative<bool>(value))
return "bool";
if (std::holds_alternative<std::chrono::seconds>(value))
return "time_length";
if (std::holds_alternative<StorageCapability>(value))
return "capability";
if (std::holds_alternative<StorageAttribute>(value))
return "attribute";
if (std::holds_alternative<StorageStatistic>(value))
return "statistic";
if (std::holds_alternative<StorageErrorBlock>(value))
return "error_block";
if (std::holds_alternative<StorageSelftestEntry>(value))
return "selftest_entry";
return "[internal_error]";
}
[[nodiscard]] std::string get_value_type_name() const;
/// Check if this is an empty object with no value set.
[[nodiscard]] bool empty() const
{
return std::holds_alternative<std::monostate>(value);
}
[[nodiscard]] bool empty() const;
/// Dump the property to a stream for debugging purposes
@@ -414,43 +276,24 @@ class StorageProperty {
/// Get value of type T
template<typename T>
const T& get_value() const
{
return std::get<T>(value);
}
const T& get_value() const;
/// Check if value is of type T
template<typename T>
[[nodiscard]] bool is_value_type() const
{
return std::holds_alternative<T>(value);
}
[[nodiscard]] bool is_value_type() const;
/// Get property description (used in tooltips)
[[nodiscard]] std::string get_description(bool clean = false) const
{
if (clean)
return this->description;
return (this->description.empty() ? "No description available" : this->description);
}
[[nodiscard]] std::string get_description(bool clean = false) const;
/// Set property description (used in tooltips)
void set_description(const std::string& descr)
{
this->description = descr;
}
void set_description(const std::string& descr);
/// Set smartctl-reported name, generic (internal) name, readable name
void set_name(const std::string& rep_name, const std::string& gen_name = "", const std::string& read_name = "")
{
this->reported_name = rep_name;
this->generic_name = (gen_name.empty() ? this->reported_name : gen_name);
this->displayable_name = (read_name.empty() ? this->reported_name : read_name);
}
void set_name(const std::string& rep_name, const std::string& gen_name = "", const std::string& read_name = "");
std::string reported_name; ///< Property name as reported by smartctl.
@@ -471,11 +314,11 @@ class StorageProperty {
int64_t, ///< Value (if it's an integer)
bool, ///< Value (if it's bool)
std::chrono::seconds, ///< Value in seconds (if it's time interval)
StorageCapability, ///< Value (if it's a capability)
StorageAttribute, ///< Value (if it's an attribute)
StorageStatistic, ///< Value (if it's a statistic from devstat)
StorageErrorBlock, ///< Value (if it's a error block)
StorageSelftestEntry ///< Value (if it's a self-test entry)
AtaStorageCapability, ///< Value (if it's a capability)
AtaStorageAttribute, ///< Value (if it's an attribute)
AtaStorageStatistic, ///< Value (if it's a statistic from devstat)
AtaStorageErrorBlock, ///< Value (if it's a error block)
AtaStorageSelftestEntry ///< Value (if it's a self-test entry)
> value;
WarningLevel warning = WarningLevel::none; ///< Warning severity for this property
@@ -489,14 +332,31 @@ class StorageProperty {
/// Output operator for debug purposes
inline std::ostream& operator<< (std::ostream& os, const StorageProperty& p)
std::ostream& operator<< (std::ostream& os, const AtaStorageProperty& p);
// ------------------------------------------- Implementation
template<typename T>
const T& AtaStorageProperty::get_value() const
{
p.dump(os);
return os;
return std::get<T>(value);
}
template<typename T>
bool AtaStorageProperty::is_value_type() const
{
return std::holds_alternative<T>(value);
}
File diff suppressed because it is too large Load Diff
@@ -9,19 +9,19 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef STORAGE_PROPERTY_DESCR_H
#define STORAGE_PROPERTY_DESCR_H
#ifndef ATA_STORAGE_PROPERTY_DESCR_H
#define ATA_STORAGE_PROPERTY_DESCR_H
#include "storage_property.h"
#include "ata_storage_property.h"
/// Fill the property with all the information we can gather (description, etc...).
bool storage_property_autoset_description(StorageProperty& p, StorageAttribute::DiskType disk_type);
bool ata_storage_property_autoset_description(AtaStorageProperty& p, AtaStorageAttribute::DiskType disk_type);
/// Do some basic checks on the property and set warnings if needed.
WarningLevel storage_property_autoset_warning(StorageProperty& p);
WarningLevel ata_storage_property_autoset_warning(AtaStorageProperty& p);
@@ -20,8 +20,8 @@ Copyright:
#include "libdebug/libdebug.h"
#include "hz/fs.h"
#include "applib/storage_property.h"
#include "applib/smartctl_parser.h"
#include "applib/ata_storage_property.h"
#include "applib/smartctl_text_parser.h"
@@ -42,13 +42,13 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
SmartctlParser sp;
if (!sp.parse_full(contents, StorageAttribute::DiskType::Any)) {
SmartctlTextParser sp;
if (!sp.parse_full(contents, AtaStorageAttribute::DiskType::Any)) {
debug_out_error("app", "Cannot parse file contents: " << sp.get_error_msg() << "\n");
return EXIT_FAILURE;
}
const std::vector<StorageProperty>& props = sp.get_properties();
const std::vector<AtaStorageProperty>& props = sp.get_properties();
for(const auto& prop : props) {
debug_out_dump("app", prop << "\n");
}
+18 -18
View File
@@ -15,8 +15,8 @@ Copyright:
#include <chrono>
#include "app_pcrecpp.h"
#include "storage_property.h"
#include "smartctl_parser.h"
#include "ata_storage_property.h"
#include "smartctl_text_parser.h"
#include "selftest.h"
@@ -75,8 +75,8 @@ std::chrono::seconds SelfTest::get_min_duration_seconds() const
case TestType::conveyance: prop_name = "conveyance_total_time_length"; break;
}
StorageProperty p = drive_->lookup_property(prop_name,
StorageProperty::Section::data, StorageProperty::SubSection::capabilities);
AtaStorageProperty p = drive_->lookup_property(prop_name,
AtaStorageProperty::Section::data, AtaStorageProperty::SubSection::capabilities);
// p stores it as uint64_t
return (total_duration_ = (p.empty() ? 0s : p.get_value<std::chrono::seconds>()));
@@ -104,7 +104,7 @@ bool SelfTest::is_supported() const
case TestType::conveyance: prop_name = "conveyance_support"; break;
}
StorageProperty p = drive_->lookup_property(prop_name, StorageProperty::Section::internal);
AtaStorageProperty p = drive_->lookup_property(prop_name, AtaStorageProperty::Section::internal);
return (!p.empty() && p.get_value<bool>());
}
@@ -155,7 +155,7 @@ std::string SelfTest::start(const std::shared_ptr<CommandExecutor>& smartctl_ex)
// Set up everything so that the caller won't have to.
status_ = StorageSelftestEntry::Status::in_progress;
status_ = AtaStorageSelftestEntry::Status::in_progress;
remaining_percent_ = 100;
// set to 90 to avoid the 100->90 timer reset. this way we won't be looking at
@@ -186,7 +186,7 @@ std::string SelfTest::force_stop(const std::shared_ptr<CommandExecutor>& smartct
// any command (e.g. "--abort") will abort it. If it has "Suspend Offline...",
// there's no way to abort such test.
if (type_ == TestType::immediate_offline) {
StorageProperty p = drive_->lookup_property("iodc_command_suspends", StorageProperty::Section::internal);
AtaStorageProperty p = drive_->lookup_property("iodc_command_suspends", AtaStorageProperty::Section::internal);
if (!p.empty() && p.get_value<bool>()) { // if empty, give a chance to abort anyway.
return _("Aborting this test is unsupported by the drive.");
}
@@ -210,8 +210,8 @@ std::string SelfTest::force_stop(const std::shared_ptr<CommandExecutor>& smartct
// the thing is, update() may fail to actually update the statuses, so
// do it manually.
if (status_ == StorageSelftestEntry::Status::in_progress) { // update() couldn't do its job
status_ = StorageSelftestEntry::Status::aborted_by_host;
if (status_ == AtaStorageSelftestEntry::Status::in_progress) { // update() couldn't do its job
status_ = AtaStorageSelftestEntry::Status::aborted_by_host;
remaining_percent_ = -1;
last_seen_percent_ = -1;
poll_in_seconds_ = std::chrono::seconds(-1);
@@ -242,8 +242,8 @@ std::string SelfTest::update(const std::shared_ptr<CommandExecutor>& smartctl_ex
if (!error_msg.empty()) // checks for empty output too
return error_msg;
StorageAttribute::DiskType disk_type = drive_->get_is_hdd() ? StorageAttribute::DiskType::Hdd : StorageAttribute::DiskType::Ssd;
SmartctlParser ps;
AtaStorageAttribute::DiskType disk_type = drive_->get_is_hdd() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd;
SmartctlTextParser ps;
if (!ps.parse_full(output, disk_type)) { // try to parse it
return ps.get_error_msg();
}
@@ -251,11 +251,11 @@ std::string SelfTest::update(const std::shared_ptr<CommandExecutor>& smartctl_ex
// Note: Since the self-test log is sometimes late
// and in undetermined order (sorting by hours is too rough),
// we use the "self-test status" capability.
StorageProperty p;
AtaStorageProperty p;
for (const auto& e : ps.get_properties()) {
// if (e.section != StorageProperty::Section::data || e.subsection != StorageProperty::SubSection::selftest_log
if (e.section != StorageProperty::Section::internal
|| !e.is_value_type<StorageSelftestEntry>() || e.get_value<StorageSelftestEntry>().test_num != 0
// if (e.section != AtaStorageProperty::Section::data || e.subsection != AtaStorageProperty::SubSection::selftest_log
if (e.section != AtaStorageProperty::Section::internal
|| !e.is_value_type<AtaStorageSelftestEntry>() || e.get_value<AtaStorageSelftestEntry>().test_num != 0
|| e.generic_name != "last_selftest_status")
continue;
p = e;
@@ -264,15 +264,15 @@ std::string SelfTest::update(const std::shared_ptr<CommandExecutor>& smartctl_ex
if (p.empty())
return _("The drive doesn't report the test status.");
status_ = p.get_value<StorageSelftestEntry>().status;
bool active = (status_ == StorageSelftestEntry::Status::in_progress);
status_ = p.get_value<AtaStorageSelftestEntry>().status;
bool active = (status_ == AtaStorageSelftestEntry::Status::in_progress);
// Note that the test needs 90% to complete, not 100. It starts at 90%
// and reaches 00% on completion. That's 9 pieces.
if (active) {
remaining_percent_ = p.get_value<StorageSelftestEntry>().remaining_percent;
remaining_percent_ = p.get_value<AtaStorageSelftestEntry>().remaining_percent;
if (remaining_percent_ != last_seen_percent_) {
last_seen_percent_ = remaining_percent_;
timer_.start(); // restart the timer
+3 -3
View File
@@ -49,7 +49,7 @@ class SelfTest {
/// Check if the test is currently active
bool is_active() const
{
return (status_ == StorageSelftestEntry::Status::in_progress);
return (status_ == AtaStorageSelftestEntry::Status::in_progress);
}
@@ -74,7 +74,7 @@ class SelfTest {
/// Get test status
StorageSelftestEntry::Status get_status() const
AtaStorageSelftestEntry::Status get_status() const
{
return status_;
}
@@ -117,7 +117,7 @@ class SelfTest {
TestType type_ = TestType::short_test; ///< Test type
// status variables:
StorageSelftestEntry::Status status_ = StorageSelftestEntry::Status::unknown; ///< Current status of the test as reported by the drive
AtaStorageSelftestEntry::Status status_ = AtaStorageSelftestEntry::Status::unknown; ///< Current status of the test as reported by the drive
int8_t remaining_percent_ = -1; ///< Remaining %. 0 means unknown, -1 means N/A. This is set to 100 on start.
int8_t last_seen_percent_ = -1; ///< Last reported %, to detect changes in percentage (needed for timer update).
mutable std::chrono::seconds total_duration_ = std::chrono::seconds(-1); ///< Total duration needed for the test, as reported by the drive. Constant. This variable acts as a cache.
+1 -1
View File
@@ -82,7 +82,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
// check every bit
for (unsigned int i = 0; i <= 7; i++) {
if (status & (1 << i)) {
if ( (status & (1 << i)) != 0 ) {
if (!str.empty())
str += "\n"; // new-line-separate each entry
str += table[i];
@@ -20,9 +20,9 @@ Copyright:
#include "hz/debug.h" // debug_*
#include "app_pcrecpp.h"
#include "smartctl_parser.h"
#include "storage_property_descr.h"
#include "storage_property_colors.h"
#include "smartctl_text_parser.h"
#include "ata_storage_property_descr.h"
#include "warning_colors.h"
@@ -31,25 +31,25 @@ namespace {
/// Get storage property by checksum error name (which corresponds to
/// an output section).
inline StorageProperty app_get_checksum_error_property(const std::string& name)
inline AtaStorageProperty app_get_checksum_error_property(const std::string& name)
{
StorageProperty p;
p.section = StorageProperty::Section::data;
AtaStorageProperty p;
p.section = AtaStorageProperty::Section::data;
if (name == "Attribute Data") {
p.subsection = StorageProperty::SubSection::attributes;
p.subsection = AtaStorageProperty::SubSection::attributes;
p.set_name(name, "attribute_data_checksum_error");
} else if (name == "Attribute Thresholds") {
p.subsection = StorageProperty::SubSection::attributes;
p.subsection = AtaStorageProperty::SubSection::attributes;
p.set_name(name, "attribute_thresholds_checksum_error");
} else if (name == "ATA Error Log") {
p.subsection = StorageProperty::SubSection::error_log;
p.subsection = AtaStorageProperty::SubSection::error_log;
p.set_name(name, "ata_error_log_checksum_error");
} else if (name == "Self-Test Log") {
p.subsection = StorageProperty::SubSection::selftest_log;
p.subsection = AtaStorageProperty::SubSection::selftest_log;
p.set_name(name, "selftest_log_checksum_error");
}
@@ -67,7 +67,7 @@ namespace {
// Parse full "smartctl -x" output
bool SmartctlParser::parse_full(const std::string& full, StorageAttribute::DiskType disk_type)
bool SmartctlTextParser::parse_full(const std::string& full, AtaStorageAttribute::DiskType disk_type)
{
this->clear(); // clear previous data
@@ -214,19 +214,19 @@ bool SmartctlParser::parse_full(const std::string& full, StorageAttribute::DiskT
}
{
StorageProperty p;
AtaStorageProperty p;
p.set_name("Smartctl version", "smartctl_version", "Smartctl Version");
p.reported_value = version;
p.value = p.reported_value; // string-type value
p.section = StorageProperty::Section::info; // add to info section
p.section = AtaStorageProperty::Section::info; // add to info section
add_property(p);
}
{
StorageProperty p;
AtaStorageProperty p;
p.set_name("Smartctl version", "smartctl_version_full", "Smartctl Version");
p.reported_value = version_full;
p.value = p.reported_value; // string-type value
p.section = StorageProperty::Section::info; // add to info section
p.section = AtaStorageProperty::Section::info; // add to info section
add_property(p);
}
@@ -276,7 +276,7 @@ bool SmartctlParser::parse_full(const std::string& full, StorageAttribute::DiskT
// Supply output of "smartctl --version" here.
// returns false on failure. Non-unix newlines in s are ok.
bool SmartctlParser::parse_version(const std::string& s, std::string& version, std::string& version_full)
bool SmartctlTextParser::parse_version(const std::string& s, std::string& version, std::string& version_full)
{
// e.g.
// "smartctl version 5.37"
@@ -296,7 +296,7 @@ bool SmartctlParser::parse_version(const std::string& s, std::string& version, s
// check that the version of smartctl output can be parsed with this parser.
bool SmartctlParser::check_parsed_version(const std::string& version_str, [[maybe_unused]] const std::string& version_full_str)
bool SmartctlTextParser::check_parsed_version(const std::string& version_str, [[maybe_unused]] const std::string& version_full_str)
{
// tested with 5.1-xx versions (1 - 18), and 5.[20 - 38].
// note: 5.1-11 (maybe others too) with scsi disk gives non-parsable output (why?).
@@ -318,7 +318,7 @@ bool SmartctlParser::check_parsed_version(const std::string& version_str, [[mayb
// convert e.g. "1,000,204,886,016 bytes" to 1.00 TB [931.51 GiB, 1000204886016 bytes].
// Note: this property is present since 5.33.
std::string SmartctlParser::parse_byte_size(const std::string& str, int64_t& bytes, bool extended)
std::string SmartctlTextParser::parse_byte_size(const std::string& str, int64_t& bytes, bool extended)
{
// E.g. "500,107,862,016" bytes or "80'060'424'192 bytes" or "80 026 361 856 bytes".
// French locale inserts 0xA0 as a separator (non-breaking space, _not_ a valid utf8 char).
@@ -371,7 +371,7 @@ std::string SmartctlParser::parse_byte_size(const std::string& str, int64_t& byt
// Parse the section part (with "=== .... ===" header) - info or data sections.
bool SmartctlParser::parse_section(const std::string& header, const std::string& body)
bool SmartctlTextParser::parse_section(const std::string& header, const std::string& body)
{
if (app_pcre_match("/START OF INFORMATION SECTION/mi", header)) {
return parse_section_info(body);
@@ -413,11 +413,11 @@ bool SmartctlParser::parse_section(const std::string& header, const std::string&
// ------------------------------------------------ INFO SECTION
bool SmartctlParser::parse_section_info(const std::string& body)
bool SmartctlTextParser::parse_section_info(const std::string& body)
{
this->set_data_section_info(body);
StorageProperty::Section section = StorageProperty::Section::info;
AtaStorageProperty::Section section = AtaStorageProperty::Section::info;
// split by lines.
// e.g. Device Model: ST3500630AS
@@ -438,7 +438,7 @@ bool SmartctlParser::parse_section_info(const std::string& body)
warning_msg += "\n" + line;
} else {
expecting_warning_lines = false;
StorageProperty p;
AtaStorageProperty p;
p.section = section;
p.set_name("Warning", "info_warning", "Warning");
p.reported_value = warning_msg;
@@ -500,7 +500,7 @@ http://knowledge.seagate.com/articles/en_US/FAQ/213891en
hz::string_trim(name);
hz::string_trim(value);
StorageProperty p;
AtaStorageProperty p;
p.section = section;
p.set_name(name);
p.reported_value = value;
@@ -522,10 +522,10 @@ http://knowledge.seagate.com/articles/en_US/FAQ/213891en
// Parse a component (one line) of the info section
bool SmartctlParser::parse_section_info_property(StorageProperty& p)
bool SmartctlTextParser::parse_section_info_property(AtaStorageProperty& p)
{
// ---- Info
if (p.section != StorageProperty::Section::info) {
if (p.section != AtaStorageProperty::Section::info) {
set_error_msg("Internal parser error."); // set this so we have something to display
debug_out_error("app", DBG_FUNC_MSG << "Called with non-info section!\n");
return false;
@@ -713,7 +713,7 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
// Parse the Data section (without "===" header)
bool SmartctlParser::parse_section_data(const std::string& body)
bool SmartctlTextParser::parse_section_data(const std::string& body)
{
this->set_data_section_data(body);
@@ -864,7 +864,7 @@ bool SmartctlParser::parse_section_data(const std::string& body)
// -------------------- Health
bool SmartctlParser::parse_section_data_subsection_health(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_health(const std::string& sub)
{
// Health section data (--info and --get=all):
/*
@@ -878,9 +878,9 @@ Form Factor: 2.5 inches
Device is: In smartctl database [for details use: -P show]
*/
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::health;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::health;
std::string name, value;
if (app_pcre_match("/^([^:\\n]+):[ \\t]*(.*)$/mi", sub, &name, &value)) {
@@ -907,7 +907,7 @@ Device is: In smartctl database [for details use: -P show]
// -------------------- Capabilities
bool SmartctlParser::parse_section_data_subsection_capabilities(const std::string& sub_initial)
bool SmartctlTextParser::parse_section_data_subsection_capabilities(const std::string& sub_initial)
{
// Capabilities section data:
/*
@@ -944,9 +944,9 @@ SCT capabilities: (0x003d) SCT Status supported.
SCT Data Table supported.
*/
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::capabilities;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::capabilities;
std::string sub = sub_initial;
@@ -1033,7 +1033,7 @@ SCT capabilities: (0x003d) SCT Status supported.
numvalue *= 60; // convert to seconds
// add as a time property
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(name);
// well, not really as reported, but still...
p.reported_value.append(numvalue_orig).append(" | ").append(strvalue_orig);
@@ -1046,15 +1046,15 @@ SCT capabilities: (0x003d) SCT Status supported.
cap_found = true;
// StorageCapability properties (capabilities are flag lists)
// AtaStorageCapability properties (capabilities are flag lists)
} else {
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(name);
// well, not really as reported, but still...
p.reported_value.append(numvalue_orig).append(" | ").append(strvalue_orig);
StorageCapability cap;
AtaStorageCapability cap;
cap.reported_flag_value = numvalue_orig;
cap.flag_value = static_cast<uint16_t>(numvalue); // full flag value
cap.reported_strvalue = strvalue_orig;
@@ -1087,7 +1087,7 @@ SCT capabilities: (0x003d) SCT Status supported.
// Check the capabilities for internal properties we can use.
bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& cap_prop)
bool SmartctlTextParser::parse_section_data_internal_capabilities(AtaStorageProperty& cap_prop)
{
// Some special capabilities we're interested in.
@@ -1130,14 +1130,14 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
pcrecpp::RE re_selftest_long_time = app_pcre_re("/^(Extended self-test routine recommended polling time)/mi");
pcrecpp::RE re_conv_selftest_time = app_pcre_re("/^(Conveyance self-test routine recommended polling time)/mi");
if (cap_prop.section != StorageProperty::Section::data || cap_prop.subsection != StorageProperty::SubSection::capabilities) {
if (cap_prop.section != AtaStorageProperty::Section::data || cap_prop.subsection != AtaStorageProperty::SubSection::capabilities) {
debug_out_error("app", DBG_FUNC_MSG << "Non-capability property passed.\n");
return false;
}
// Name the capability groups for easy matching when setting descriptions
if (cap_prop.is_value_type<StorageCapability>()) {
if (cap_prop.is_value_type<AtaStorageCapability>()) {
if (re_offline_status_group.PartialMatch(cap_prop.reported_name)) {
cap_prop.generic_name = "offline_status_group";
@@ -1163,16 +1163,16 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
if (re_selftest_status.PartialMatch(cap_prop.reported_name)) {
// The last self-test status. break up into pieces.
StorageProperty p;
p.section = StorageProperty::Section::internal;
AtaStorageProperty p;
p.section = AtaStorageProperty::Section::internal;
p.set_name("last_selftest_status");
StorageSelftestEntry sse;
AtaStorageSelftestEntry sse;
sse.test_num = 0;
sse.remaining_percent = -1; // unknown or n/a
// check for lines in capability vector
for (const auto& sv : cap_prop.get_value<StorageCapability>().strvalues) {
for (const auto& sv : cap_prop.get_value<AtaStorageCapability>().strvalues) {
std::string value;
if (app_pcre_match("/^([0-9]+)% of test remaining/mi", sv, &value)) {
@@ -1182,56 +1182,56 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
} else if (app_pcre_match("/^(The previous self-test routine completed without error or no .*)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::completed_no_error;
sse.status = AtaStorageSelftestEntry::Status::completed_no_error;
} else if (app_pcre_match("/^(The self-test routine was aborted by the host)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::aborted_by_host;
sse.status = AtaStorageSelftestEntry::Status::aborted_by_host;
} else if (app_pcre_match("/^(The self-test routine was interrupted by the host with a hard.*)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::interrupted;
sse.status = AtaStorageSelftestEntry::Status::interrupted;
} else if (app_pcre_match("/^(A fatal error or unknown test error occurred while the device was executing its .*)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::fatal_or_unknown;
sse.status = AtaStorageSelftestEntry::Status::fatal_or_unknown;
} else if (app_pcre_match("/^(The previous self-test completed having a test element that failed and the test element that failed is not known)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::compl_unknown_failure;
sse.status = AtaStorageSelftestEntry::Status::compl_unknown_failure;
} else if (app_pcre_match("/^(The previous self-test completed having the electrical element of the test failed)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::compl_electrical_failure;
sse.status = AtaStorageSelftestEntry::Status::compl_electrical_failure;
} else if (app_pcre_match("/^(The previous self-test completed having the servo .*)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::compl_servo_failure;
sse.status = AtaStorageSelftestEntry::Status::compl_servo_failure;
} else if (app_pcre_match("/^(The previous self-test completed having the read element of the test failed)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::compl_read_failure;
sse.status = AtaStorageSelftestEntry::Status::compl_read_failure;
} else if (app_pcre_match("/^(The previous self-test completed having a test element that failed and the device is suspected of having handling damage)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::compl_handling_damage;
sse.status = AtaStorageSelftestEntry::Status::compl_handling_damage;
// samsung bug (?), as per smartctl sources.
} else if (app_pcre_match("/^(The previous self-test routine completed with unknown result or self-test .*)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::compl_unknown_failure; // we'll use this again (correct?)
sse.status = AtaStorageSelftestEntry::Status::compl_unknown_failure; // we'll use this again (correct?)
} else if (app_pcre_match("/^(Self-test routine in progress)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::in_progress;
sse.status = AtaStorageSelftestEntry::Status::in_progress;
} else if (app_pcre_match("/^(Reserved)/mi", sv, &value)) {
sse.status_str = value;
sse.status = StorageSelftestEntry::Status::reserved;
sse.status = AtaStorageSelftestEntry::Status::reserved;
}
}
p.value = sse; // StorageSelftestEntry-type value
p.value = sse; // AtaStorageSelftestEntry-type value
add_property(p);
@@ -1262,15 +1262,15 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
// Extract subcapabilities from capability vectors and assign to "internal" section.
if (cap_prop.is_value_type<StorageCapability>()) {
if (cap_prop.is_value_type<AtaStorageCapability>()) {
// check for lines in capability vector
for (const auto& sv : cap_prop.get_value<StorageCapability>().strvalues) {
for (const auto& sv : cap_prop.get_value<AtaStorageCapability>().strvalues) {
// debug_out_dump("app", "Looking for internal capability in: \"" << sv << "\"\n");
StorageProperty p;
p.section = StorageProperty::Section::internal;
AtaStorageProperty p;
p.section = AtaStorageProperty::Section::internal;
// Note: We don't set reported_value on internal properties.
std::string name, value;
@@ -1344,11 +1344,11 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
// -------------------- Attributes
bool SmartctlParser::parse_section_data_subsection_attributes(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_attributes(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::attributes;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::attributes;
// split to lines
std::vector<std::string> lines;
@@ -1446,7 +1446,7 @@ ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE
int64_t value_num = 0;
hz::string_is_numeric_nolocale(value, value_num, false);
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(name, "data_structure_version");
p.reported_value = value;
p.value = value_num; // integer-type value
@@ -1493,7 +1493,7 @@ ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE
}
StorageAttribute attr;
AtaStorageAttribute attr;
hz::string_is_numeric_nolocale(hz::string_trim_copy(id), attr.id, true, 10);
attr.flag = hz::string_trim_copy(flag);
uint8_t norm_value = 0, worst_value = 0, threshold_value = 0;
@@ -1509,43 +1509,43 @@ ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE
}
if (attr_format_style == FormatStyleBrief) {
attr.attr_type = app_pcre_match("/P/", attr.flag) ? StorageAttribute::AttributeType::prefail : StorageAttribute::AttributeType::old_age;
attr.attr_type = app_pcre_match("/P/", attr.flag) ? AtaStorageAttribute::AttributeType::prefail : AtaStorageAttribute::AttributeType::old_age;
} else {
if (attr_type == "Pre-fail") {
attr.attr_type = StorageAttribute::AttributeType::prefail;
attr.attr_type = AtaStorageAttribute::AttributeType::prefail;
} else if (attr_type == "Old_age") {
attr.attr_type = StorageAttribute::AttributeType::old_age;
attr.attr_type = AtaStorageAttribute::AttributeType::old_age;
} else {
attr.attr_type = StorageAttribute::AttributeType::unknown;
attr.attr_type = AtaStorageAttribute::AttributeType::unknown;
}
}
if (attr_format_style == FormatStyleBrief) {
attr.update_type = app_pcre_match("/O/", attr.flag) ? StorageAttribute::UpdateType::always : StorageAttribute::UpdateType::offline;
attr.update_type = app_pcre_match("/O/", attr.flag) ? AtaStorageAttribute::UpdateType::always : AtaStorageAttribute::UpdateType::offline;
} else {
if (update_type == "Always") {
attr.update_type = StorageAttribute::UpdateType::always;
attr.update_type = AtaStorageAttribute::UpdateType::always;
} else if (update_type == "Offline") {
attr.update_type = StorageAttribute::UpdateType::offline;
attr.update_type = AtaStorageAttribute::UpdateType::offline;
} else {
attr.update_type = StorageAttribute::UpdateType::unknown;
attr.update_type = AtaStorageAttribute::UpdateType::unknown;
}
}
attr.when_failed = StorageAttribute::FailTime::unknown;
attr.when_failed = AtaStorageAttribute::FailTime::unknown;
hz::string_trim(when_failed);
if (when_failed == "-") {
attr.when_failed = StorageAttribute::FailTime::none;
attr.when_failed = AtaStorageAttribute::FailTime::none;
} else if (when_failed == "In_the_past" || when_failed == "Past") { // the second one if from brief format
attr.when_failed = StorageAttribute::FailTime::past;
attr.when_failed = AtaStorageAttribute::FailTime::past;
} else if (when_failed == "FAILING_NOW" || when_failed == "NOW") { // the second one if from brief format
attr.when_failed = StorageAttribute::FailTime::now;
attr.when_failed = AtaStorageAttribute::FailTime::now;
}
attr.raw_value = hz::string_trim_copy(raw_value);
hz::string_is_numeric_nolocale(hz::string_trim_copy(raw_value), attr.raw_value_int, false); // same as raw_value, but parsed as int.
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(hz::string_trim_copy(name));
p.reported_value = line; // use the whole line here
p.value = attr; // attribute-type value;
@@ -1564,11 +1564,11 @@ ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE
bool SmartctlParser::parse_section_data_subsection_directory_log(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_directory_log(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::directory_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::directory_log;
// Directory log contains:
/*
@@ -1589,7 +1589,7 @@ Address Access R/W Size Description
// the whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("General Purpose Log Directory", "directory_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -1600,7 +1600,7 @@ Address Access R/W Size Description
// supported / unsupported
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("General Purpose Log Directory supported", "directory_log_supported");
// p.reported_value; // nothing
@@ -1616,11 +1616,11 @@ Address Access R/W Size Description
bool SmartctlParser::parse_section_data_subsection_error_log(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_error_log(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::error_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::error_log;
// Note: The format of this section was changed somewhere between 5.0-x and 5.30.
// The old format is doesn't really give any useful info, and whatever's left is somewhat
@@ -1676,7 +1676,7 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
hz::string_trim(name);
hz::string_trim(value);
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(name, "error_log_version");
p.reported_value = value;
@@ -1694,7 +1694,7 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
pcrecpp::RE re = app_pcre_re("/^(Warning: device does not support Error Logging)|(SMART Error Log not supported)$/mi");
if (re.PartialMatch(sub)) {
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("error_log_unsupported");
p.displayable_name = "Warning";
p.readable_value = "Device does not support error logging";
@@ -1712,7 +1712,7 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
if (re1.PartialMatch(sub, &value) || re2.PartialMatch(sub)) {
hz::string_trim(value);
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("ATA Error Count", "error_log_error_count");
p.reported_value = value;
@@ -1756,11 +1756,11 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
re_state.PartialMatch(block, &state);
re_type.PartialMatch(block, &etypes_str, &emore);
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(hz::string_trim_copy(name)); // "Error 6"
p.reported_value = block;
StorageErrorBlock eb;
AtaStorageErrorBlock eb;
hz::string_is_numeric_nolocale(value_num, eb.error_num, false);
hz::string_is_numeric_nolocale(value_time, eb.lifetime_hours, false);
@@ -1785,7 +1785,7 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
// the whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SMART Error Log", "error_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -1805,11 +1805,11 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
// -------------------- Selftest Log
bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_selftest_log(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::selftest_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::selftest_log;
// Self-test log contains:
// * structure revision number
@@ -1832,7 +1832,7 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
// The whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SMART Self-Test Log", "selftest_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -1847,7 +1847,7 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
pcrecpp::RE re = app_pcre_re("/^(Warning: device does not support Self Test Logging)|(SMART Self-test Log not supported)$/mi");
if (re.PartialMatch(sub)) {
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("selftest_log_unsupported");
p.displayable_name = "Warning";
p.readable_value = "Device does not support self-test logging";
@@ -1870,7 +1870,7 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
if (re1.PartialMatch(sub, &name, &value) || re1_ex.PartialMatch(sub, &name, &value) || re2.PartialMatch(sub, &name, &value)) {
hz::string_trim(value);
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(hz::string_trim_copy(name), "selftest_log_version");
p.reported_value = value;
@@ -1900,11 +1900,11 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
while (re.FindAndConsume(&input, &line, &num, &type, &status_str, &remaining, &hours, &lba)) {
hz::string_trim(num);
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("Self-test entry " + num);
p.reported_value = hz::string_trim_copy(line);
StorageSelftestEntry sse;
AtaStorageSelftestEntry sse;
hz::string_is_numeric_nolocale(num, sse.test_num, false);
hz::string_is_numeric_nolocale(hz::string_trim_copy(remaining), sse.remaining_percent, false);
@@ -1917,37 +1917,37 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
sse.lba_of_first_error = "-";
hz::string_trim(status_str);
StorageSelftestEntry::Status status = StorageSelftestEntry::Status::unknown;
AtaStorageSelftestEntry::Status status = AtaStorageSelftestEntry::Status::unknown;
// don't match end - some of them are not complete here
if (app_pcre_match("/^Completed without error/mi", status_str)) {
status = StorageSelftestEntry::Status::completed_no_error;
status = AtaStorageSelftestEntry::Status::completed_no_error;
} else if (app_pcre_match("/^Aborted by host/mi", status_str)) {
status = StorageSelftestEntry::Status::aborted_by_host;
status = AtaStorageSelftestEntry::Status::aborted_by_host;
} else if (app_pcre_match("/^Interrupted \\(host reset\\)/mi", status_str)) {
status = StorageSelftestEntry::Status::interrupted;
status = AtaStorageSelftestEntry::Status::interrupted;
} else if (app_pcre_match("/^Fatal or unknown error/mi", status_str)) {
status = StorageSelftestEntry::Status::fatal_or_unknown;
status = AtaStorageSelftestEntry::Status::fatal_or_unknown;
} else if (app_pcre_match("/^Completed: unknown failure/mi", status_str)) {
status = StorageSelftestEntry::Status::compl_unknown_failure;
status = AtaStorageSelftestEntry::Status::compl_unknown_failure;
} else if (app_pcre_match("/^Completed: electrical failure/mi", status_str)) {
status = StorageSelftestEntry::Status::compl_electrical_failure;
status = AtaStorageSelftestEntry::Status::compl_electrical_failure;
} else if (app_pcre_match("/^Completed: servo\\/seek failure/mi", status_str)) {
status = StorageSelftestEntry::Status::compl_servo_failure;
status = AtaStorageSelftestEntry::Status::compl_servo_failure;
} else if (app_pcre_match("/^Completed: read failure/mi", status_str)) {
status = StorageSelftestEntry::Status::compl_read_failure;
status = AtaStorageSelftestEntry::Status::compl_read_failure;
} else if (app_pcre_match("/^Completed: handling damage/mi", status_str)) {
status = StorageSelftestEntry::Status::compl_handling_damage;
status = AtaStorageSelftestEntry::Status::compl_handling_damage;
} else if (app_pcre_match("/^Self-test routine in progress/mi", status_str)) {
status = StorageSelftestEntry::Status::in_progress;
status = AtaStorageSelftestEntry::Status::in_progress;
} else if (app_pcre_match("/^Unknown\\/reserved test status/mi", status_str)) {
status = StorageSelftestEntry::Status::reserved;
status = AtaStorageSelftestEntry::Status::reserved;
}
sse.status_str = status_str;
sse.status = status;
p.value = sse; // StorageSelftestEntry value
p.value = sse; // AtaStorageSelftestEntry value
add_property(p);
data_found = true;
@@ -1960,7 +1960,7 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
// number of tests.
// Note: "No self-tests have been logged" is sometimes absent, so don't rely on it.
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("Number of entries in self-test log", "selftest_num_entries");
// p.reported_value; // nothing
p.value = test_count; // integer
@@ -1981,11 +1981,11 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
// -------------------- Selective Selftest Log
bool SmartctlParser::parse_section_data_subsection_selective_selftest_log(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_selective_selftest_log(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::selective_selftest_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::selective_selftest_log;
// Selective self-test log contains:
/*
@@ -2005,7 +2005,7 @@ If Selective self-test is pending on power-up, resume after 0 minute delay.
// the whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SMART Selective self-test log", "SubSection::selective_selftest_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -2016,7 +2016,7 @@ If Selective self-test is pending on power-up, resume after 0 minute delay.
// supported / unsupported
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("Selective self-tests supported", "selective_selftest_supported");
// p.reported_value; // nothing
@@ -2034,11 +2034,11 @@ If Selective self-test is pending on power-up, resume after 0 minute delay.
bool SmartctlParser::parse_section_data_subsection_scttemp_log(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_scttemp_log(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::temperature_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::temperature_log;
// scttemp log contains:
/*
@@ -2075,7 +2075,7 @@ Index Estimated Time Temperature Celsius
// the whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SCT temperature log", "scttemp_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -2086,7 +2086,7 @@ Index Estimated Time Temperature Celsius
// supported / unsupported
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SCT commands unsupported", "sct_unsupported");
// p.reported_value; // nothing
@@ -2103,9 +2103,9 @@ Index Estimated Time Temperature Celsius
{
std::string name, value;
if (app_pcre_match("/^(Current Temperature):[ \\t]+(.*) Celsius$/mi", sub, &name, &value)) {
StorageProperty p;
p.section = StorageProperty::Section::data;
p.subsection = StorageProperty::SubSection::temperature_log;
AtaStorageProperty p;
p.section = AtaStorageProperty::Section::data;
p.subsection = AtaStorageProperty::SubSection::temperature_log;
p.set_name("Current Temperature", "sct_temperature_celsius");
p.reported_value = value;
p.value = hz::string_to_number_nolocale<int64_t>(value); // integer
@@ -2120,11 +2120,11 @@ Index Estimated Time Temperature Celsius
bool SmartctlParser::parse_section_data_subsection_scterc_log(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_scterc_log(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::erc_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::erc_log;
// scterc log contains:
/*
@@ -2136,7 +2136,7 @@ SCT Error Recovery Control:
// the whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SCT ERC log", "scterc_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -2147,7 +2147,7 @@ SCT Error Recovery Control:
// supported / unsupported
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SCT ERC supported", "sct_erc_supported");
// p.reported_value; // nothing
@@ -2165,11 +2165,11 @@ SCT Error Recovery Control:
bool SmartctlParser::parse_section_data_subsection_devstat(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_devstat(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::devstat;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::devstat;
// devstat log contains:
/*
@@ -2216,7 +2216,7 @@ Page Offset Size Value Description
// supported / unsupported
bool supported = true;
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("Device statistics supported", "devstat_supported");
// p.reported_value; // nothing
@@ -2306,7 +2306,7 @@ Page Offset Size Value Description
}
StorageStatistic st;
AtaStorageStatistic st;
st.is_header = (hz::string_trim_copy(value) == "=");
st.flags = st.is_header ? std::string() : hz::string_trim_copy(flags);
st.value = st.is_header ? std::string() : hz::string_trim_copy(value);
@@ -2318,7 +2318,7 @@ Page Offset Size Value Description
description = hz::string_trim_copy(hz::string_trim_copy(description, "="));
}
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name(hz::string_trim_copy(description));
p.reported_value = line; // use the whole line here
p.value = st; // statistic-type value
@@ -2335,11 +2335,11 @@ Page Offset Size Value Description
bool SmartctlParser::parse_section_data_subsection_sataphy(const std::string& sub)
bool SmartctlTextParser::parse_section_data_subsection_sataphy(const std::string& sub)
{
StorageProperty pt; // template for easy copying
pt.section = StorageProperty::Section::data;
pt.subsection = StorageProperty::SubSection::phy_log;
AtaStorageProperty pt; // template for easy copying
pt.section = AtaStorageProperty::Section::data;
pt.subsection = AtaStorageProperty::SubSection::phy_log;
// sataphy log contains:
/*
@@ -2359,7 +2359,7 @@ ID Size Value Description
// the whole subsection
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SATA Phy log", "sataphy_log");
p.reported_value = sub;
p.value = p.reported_value; // string-type value
@@ -2370,7 +2370,7 @@ ID Size Value Description
// supported / unsupported
{
StorageProperty p(pt);
AtaStorageProperty p(pt);
p.set_name("SATA Phy log supported", "sataphy_supported");
// p.reported_value; // nothing
@@ -2389,21 +2389,21 @@ ID Size Value Description
std::string SmartctlParser::get_data_full() const
std::string SmartctlTextParser::get_data_full() const
{
return data_full_;
}
std::string SmartctlParser::get_error_msg() const
std::string SmartctlTextParser::get_error_msg() const
{
return Glib::ustring::compose(_("Cannot parse smartctl output: %1"), error_msg_);
}
const std::vector<StorageProperty>& SmartctlParser::get_properties() const
const std::vector<AtaStorageProperty>& SmartctlTextParser::get_properties() const
{
return properties_;
}
@@ -2412,10 +2412,10 @@ const std::vector<StorageProperty>& SmartctlParser::get_properties() const
// adds a property into property list, looks up and sets its description.
// Yes, there's no place for this in the Parser, but whatever...
void SmartctlParser::add_property(StorageProperty p)
void SmartctlTextParser::add_property(AtaStorageProperty p)
{
storage_property_autoset_description(p, disk_type_);
storage_property_autoset_warning(p);
ata_storage_property_autoset_description(p, disk_type_);
ata_storage_property_autoset_warning(p);
storage_property_autoset_warning_descr(p); // append warning to description
properties_.push_back(p);
@@ -2423,28 +2423,28 @@ void SmartctlParser::add_property(StorageProperty p)
void SmartctlParser::set_data_full(const std::string& s)
void SmartctlTextParser::set_data_full(const std::string& s)
{
data_full_ = s;
}
void SmartctlParser::set_data_section_info(const std::string& s)
void SmartctlTextParser::set_data_section_info(const std::string& s)
{
data_section_info_ = s;
}
void SmartctlParser::set_data_section_data(const std::string& s)
void SmartctlTextParser::set_data_section_data(const std::string& s)
{
data_section_data_ = s;
}
void SmartctlParser::set_error_msg(const std::string& s)
void SmartctlTextParser::set_error_msg(const std::string& s)
{
error_msg_ = s;
}
@@ -9,24 +9,24 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef SMARTCTL_PARSER_H
#define SMARTCTL_PARSER_H
#ifndef SMARTCTL_TEXT_PARSER_H
#define SMARTCTL_TEXT_PARSER_H
#include <string>
#include <vector>
#include "storage_property.h"
#include "ata_storage_property.h"
/// Smartctl parser.
/// Note: ALL parse_* functions (except parse_full() and parse_version())
/// expect data in unix-newline format!
class SmartctlParser {
class SmartctlTextParser {
public:
/// Parse full "smartctl -x" output
bool parse_full(const std::string& full, StorageAttribute::DiskType disk_type);
bool parse_full(const std::string& full, AtaStorageAttribute::DiskType disk_type);
/// Supply any output of smartctl here, the smartctl version will be retrieved.
@@ -53,7 +53,7 @@ class SmartctlParser {
bool parse_section_info(const std::string& body);
/// Parse a component (one line) of the info section
bool parse_section_info_property(StorageProperty& p);
bool parse_section_info_property(AtaStorageProperty& p);
/// Parse the Data section (without "===" header)
@@ -73,7 +73,7 @@ class SmartctlParser {
bool parse_section_data_subsection_sataphy(const std::string& sub);
/// Check the capabilities for internal properties we can use.
bool parse_section_data_internal_capabilities(StorageProperty& cap_prop);
bool parse_section_data_internal_capabilities(AtaStorageProperty& cap_prop);
/// Clear parsed data
@@ -109,7 +109,7 @@ class SmartctlParser {
/// Get parse result properties
[[nodiscard]] const std::vector<StorageProperty>& get_properties() const;
[[nodiscard]] const std::vector<AtaStorageProperty>& get_properties() const;
@@ -117,7 +117,7 @@ class SmartctlParser {
/// Add a property into property list, look up and set its description
void add_property(StorageProperty p);
void add_property(AtaStorageProperty p);
/// Set "full" data ("smartctl -x" output)
@@ -137,7 +137,7 @@ class SmartctlParser {
std::vector<StorageProperty> properties_; ///< Parsed data properties
std::vector<AtaStorageProperty> properties_; ///< Parsed data properties
std::string data_full_; ///< full data, filled by parse_full()
std::string data_section_info_; ///< "info" section data, filled by parse_section_info()
@@ -145,7 +145,7 @@ class SmartctlParser {
std::string error_msg_; ///< This will be filled with some displayable message on error
StorageAttribute::DiskType disk_type_ = StorageAttribute::DiskType::Any; ///< Disk type (HDD, SSD)
AtaStorageAttribute::DiskType disk_type_ = AtaStorageAttribute::DiskType::Any; ///< Disk type (HDD, SSD)
};
+34 -27
View File
@@ -19,7 +19,7 @@ Copyright:
#include "app_pcrecpp.h"
#include "storage_device.h"
#include "smartctl_parser.h"
#include "smartctl_text_parser.h"
#include "storage_settings.h"
#include "smartctl_executor.h"
@@ -145,7 +145,7 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
}
std::string version, version_full;
if (!SmartctlParser::parse_version(this->info_output_, version, version_full)) // is this smartctl data at all?
if (!SmartctlTextParser::parse_version(this->info_output_, version, version_full)) // is this smartctl data at all?
return _("Cannot get smartctl version information.");
// Detect type. note: we can't distinguish between sata and scsi (on linux, for -d ata switch).
@@ -171,10 +171,10 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
smart_enabled_ = false;
} else {
// Note: We don't use SmartctlParser here, because this information
// Note: We don't use SmartctlTextParser here, because this information
// may be in some other format. If this information is valid, only then it's
// passed to SmartctlParser.
// Compared to SmartctlParser, this one is much looser.
// passed to SmartctlTextParser.
// Compared to SmartctlTextParser, this one is much looser.
// Don't put complete messages here - they change across smartctl versions.
if (app_pcre_match("/^SMART support is:[ \\t]*Unavailable/mi", info_output_) // cdroms output this
@@ -225,7 +225,7 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
std::string size;
if (app_pcre_match("/^User Capacity:[ \\t]*(.*)$/mi", info_output_, &size)) {
int64_t bytes = 0;
size_ = SmartctlParser::parse_byte_size(size, bytes, false);
size_ = SmartctlTextParser::parse_byte_size(size, bytes, false);
}
@@ -233,11 +233,11 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
// Note that this may try to parse data the second time (it may already have
// been parsed by parse_data() which failed at it).
if (do_set_properties) {
StorageAttribute::DiskType disk_type = StorageAttribute::DiskType::Any;
AtaStorageAttribute::DiskType disk_type = AtaStorageAttribute::DiskType::Any;
if (hdd_.has_value()) {
disk_type = hdd_.value() ? StorageAttribute::DiskType::Hdd : StorageAttribute::DiskType::Ssd;
disk_type = hdd_.value() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd;
}
SmartctlParser ps;
SmartctlTextParser ps;
if (ps.parse_full(this->info_output_, disk_type)) { // try to parse it
this->set_properties(ps.get_properties()); // copy to our drive, overwriting old data
}
@@ -247,7 +247,7 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
set_parse_status(model_name_.has_value() ? ParseStatus::info : ParseStatus::none);
if (emit_signal)
signal_changed.emit(this); // notify listeners
signal_changed().emit(this); // notify listeners
return std::string();
}
@@ -297,18 +297,18 @@ std::string StorageDevice::parse_data()
{
this->clear_fetched(false); // clear everything fetched before, except outputs
StorageAttribute::DiskType disk_type = StorageAttribute::DiskType::Any;
AtaStorageAttribute::DiskType disk_type = AtaStorageAttribute::DiskType::Any;
if (hdd_.has_value()) {
disk_type = hdd_.value() ? StorageAttribute::DiskType::Hdd : StorageAttribute::DiskType::Ssd;
disk_type = hdd_.value() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd;
}
SmartctlParser ps;
SmartctlTextParser ps;
if (ps.parse_full(this->full_output_, disk_type)) { // try to parse it (parse only, set the properties after basic parsing).
// refresh basic info too
this->info_output_ = ps.get_data_full(); // put data including version information
// note: this will clear the non-basic properties!
// this will parse some info that is already parsed by SmartctlParser::parse_full(),
// this will parse some info that is already parsed by SmartctlTextParser::parse_full(),
// but this one sets the StorageDevice class members, not properties.
this->parse_basic_data(false, false); // don't emit signal, we're not complete yet.
@@ -318,7 +318,7 @@ std::string StorageDevice::parse_data()
// set the full properties
this->set_properties(ps.get_properties()); // copy to our drive, overwriting old data
signal_changed.emit(this); // notify listeners
signal_changed().emit(this); // notify listeners
return std::string();
}
@@ -330,7 +330,7 @@ std::string StorageDevice::parse_data()
// proper parsing failed. try to at least extract info section
this->info_output_ = this->full_output_; // complete output here. sometimes it's only the info section
if (!this->parse_basic_data(true).empty()) { // will add some properties too. this will emit signal_changed.
if (!this->parse_basic_data(true).empty()) { // will add some properties too. this will emit signal_changed().
return ps.get_error_msg(); // return full parser's error messages - they are more detailed.
}
@@ -470,7 +470,7 @@ StorageDevice::Status StorageDevice::get_aodc_status() const
int found = 0;
for (const auto& p : properties_) {
if (p.section == StorageProperty::Section::internal) {
if (p.section == AtaStorageProperty::Section::internal) {
if (p.generic_name == "aodc_enabled") { // if this is not present at all, we set the unknown status.
status = (p.get_value<bool>() ? Status::enabled : Status::disabled);
//++found;
@@ -506,13 +506,13 @@ std::string StorageDevice::get_device_size_str() const
StorageProperty StorageDevice::get_health_property() const
AtaStorageProperty StorageDevice::get_health_property() const
{
if (health_property_.has_value()) // cached return value
return health_property_.value();
StorageProperty p = this->lookup_property("overall_health",
StorageProperty::Section::data, StorageProperty::SubSection::health);
AtaStorageProperty p = this->lookup_property("overall_health",
AtaStorageProperty::Section::data, AtaStorageProperty::SubSection::health);
if (!p.empty())
health_property_ = p; // store to cache
@@ -650,25 +650,25 @@ std::string StorageDevice::get_virtual_filename() const
const std::vector<StorageProperty>& StorageDevice::get_properties() const
const std::vector<AtaStorageProperty>& StorageDevice::get_properties() const
{
return properties_;
}
StorageProperty StorageDevice::lookup_property(const std::string& generic_name, StorageProperty::Section section, StorageProperty::SubSection subsection) const
AtaStorageProperty StorageDevice::lookup_property(const std::string& generic_name, AtaStorageProperty::Section section, AtaStorageProperty::SubSection subsection) const
{
for (const auto& p : properties_) {
if (section != StorageProperty::Section::unknown && p.section != section)
if (section != AtaStorageProperty::Section::unknown && p.section != section)
continue;
if (subsection != StorageProperty::SubSection::unknown && p.subsection != subsection)
if (subsection != AtaStorageProperty::SubSection::unknown && p.subsection != subsection)
continue;
if (p.generic_name == generic_name)
return p;
}
return StorageProperty(); // check with .empty()
return AtaStorageProperty(); // check with .empty()
}
@@ -748,7 +748,7 @@ void StorageDevice::set_test_is_active(bool b)
bool changed = (test_is_active_ != b);
test_is_active_ = b;
if (changed) {
signal_changed.emit(this); // so that everybody stops any test-aborting operations.
signal_changed().emit(this); // so that everybody stops any test-aborting operations.
}
}
@@ -843,6 +843,13 @@ std::string StorageDevice::execute_device_smartctl(const std::string& command_op
sigc::signal<void, StorageDevice*>& StorageDevice::signal_changed()
{
return signal_changed_;
}
void StorageDevice::set_parse_status(ParseStatus value)
{
parse_status_ = value;
@@ -850,7 +857,7 @@ void StorageDevice::set_parse_status(ParseStatus value)
void StorageDevice::set_properties(std::vector<StorageProperty> props)
void StorageDevice::set_properties(std::vector<AtaStorageProperty> props)
{
properties_ = std::move(props);
}
+14 -11
View File
@@ -19,8 +19,8 @@ Copyright:
#include <sigc++/sigc++.h>
#include "hz/fs_ns.h"
#include "storage_property.h"
#include "smartctl_parser.h" // prop_list_t
#include "ata_storage_property.h"
#include "smartctl_text_parser.h" // prop_list_t
#include "smartctl_executor.h"
@@ -121,7 +121,7 @@ class StorageDevice {
std::string get_device_size_str() const;
/// Get the overall health property
StorageProperty get_health_property() const;
AtaStorageProperty get_health_property() const;
/// Get device name (e.g. /dev/sda)
@@ -176,13 +176,13 @@ class StorageDevice {
/// Get all detected properties
const std::vector<StorageProperty>& get_properties() const;
const std::vector<AtaStorageProperty>& get_properties() const;
/// Find a property
StorageProperty lookup_property(const std::string& generic_name,
StorageProperty::Section section = StorageProperty::Section::unknown, // if unknown, search in all.
StorageProperty::SubSection subsection = StorageProperty::SubSection::unknown) const;
AtaStorageProperty lookup_property(const std::string& generic_name,
AtaStorageProperty::Section section = AtaStorageProperty::Section::unknown, // if unknown, search in all.
AtaStorageProperty::SubSection subsection = AtaStorageProperty::SubSection::unknown) const;
/// Get model name.
@@ -244,7 +244,7 @@ class StorageDevice {
/// Emitted whenever new information is available
sigc::signal<void, StorageDevice*> signal_changed;
sigc::signal<void, StorageDevice*>& signal_changed();
protected:
@@ -253,7 +253,7 @@ class StorageDevice {
void set_parse_status(ParseStatus value);
/// Set parsed properties
void set_properties(std::vector<StorageProperty> props);
void set_properties(std::vector<AtaStorageProperty> props);
private:
@@ -287,9 +287,12 @@ class StorageDevice {
std::optional<std::string> serial_number_; ///< Serial number
std::optional<std::string> size_; ///< Formatted size
std::optional<bool> hdd_; ///< Whether it's a rotational drive (HDD) or something else (SSD, flash, etc...)
mutable std::optional<StorageProperty> health_property_; ///< Cached health property.
mutable std::optional<AtaStorageProperty> health_property_; ///< Cached health property.
std::vector<StorageProperty> properties_; ///< Smart properties. Detected through full output.
std::vector<AtaStorageProperty> properties_; ///< Smart properties. Detected through full output.
/// Emitted whenever new information is available
sigc::signal<void, StorageDevice*> signal_changed_;
};
-289
View File
@@ -1,289 +0,0 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup applib
/// \weakgroup applib
/// @{
#include "local_glibmm.h"
#include <map>
#include <ostream> // not iosfwd - it doesn't work
#include <sstream>
#include <iomanip>
#include <locale>
#include "hz/string_num.h" // number_to_string
#include "hz/stream_cast.h" // stream_cast<>
#include "hz/format_unit.h" // format_time_length
#include "hz/string_algo.h" // string_join
#include "hz/string_num.h" // number_to_string
#include "storage_property.h"
std::ostream& operator<< (std::ostream& os, const StorageCapability& p)
{
os
// << p.name << ": "
<< p.flag_value;
for (auto&& v : p.strvalues) {
os << "\n\t" << v;
}
return os;
}
std::string StorageAttribute::format_raw_value() const
{
// If it's fully a number, format it with commas
if (hz::number_to_string_nolocale(raw_value_int) == raw_value) {
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << raw_value_int;
return ss.str();
}
return raw_value;
}
std::ostream& operator<< (std::ostream& os, const StorageAttribute& p)
{
// os << p.name << ": "
if (p.value.has_value()) {
os << static_cast<int>(p.value.value());
} else {
os << "-";
}
os << " (" << p.format_raw_value() << ")";
return os;
}
std::string StorageStatistic::format_value() const
{
// If it's fully a number, format it with commas
if (hz::number_to_string_nolocale(value_int) == value) {
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << value_int;
return ss.str();
}
return value;
}
std::ostream& operator<<(std::ostream& os, const StorageStatistic& p)
{
os << p.value;
return os;
}
std::string StorageErrorBlock::get_displayable_error_types(const std::vector<std::string>& types)
{
static const std::map<std::string, std::string> m = {
{"ABRT", _("Command aborted")},
{"AMNF", _("Address mark not found")},
{"CCTO", _("Command completion timed out")},
{"EOM", _("End of media")},
{"ICRC", _("Interface CRC error")},
{"IDNF", _("Identity not found")},
{"ILI", _("(Packet command-set specific)")},
{"MC", _("Media changed")},
{"MCR", _("Media change request")},
{"NM", _("No media")},
{"obs", _("Obsolete")},
{"TK0NF", _("Track 0 not found")},
{"UNC", _("Uncorrectable error in data")},
{"WP", _("Media is write protected")},
};
std::vector<std::string> sv;
for (const auto& type : types) {
if (m.find(type) != m.end()) {
sv.push_back(m.at(type));
} else {
std::string name = _("Uknown type");
if (!type.empty()) {
name = Glib::ustring::compose(_("Uknown type: %1"), type);
}
sv.push_back(name);
}
}
return hz::string_join(sv, _(", "));
}
WarningLevel StorageErrorBlock::get_warning_level_for_error_type(const std::string& type)
{
static const std::map<std::string, WarningLevel> m = {
{"ABRT", WarningLevel::none},
{"AMNF", WarningLevel::alert},
{"CCTO", WarningLevel::warning},
{"EOM", WarningLevel::warning},
{"ICRC", WarningLevel::warning},
{"IDNF", WarningLevel::alert},
{"ILI", WarningLevel::notice},
{"MC", WarningLevel::none},
{"MCR", WarningLevel::none},
{"NM", WarningLevel::none},
{"obs", WarningLevel::none},
{"TK0NF", WarningLevel::alert},
{"UNC", WarningLevel::alert},
{"WP", WarningLevel::none},
};
if (m.find(type) != m.end()) {
return m.at(type);
}
return WarningLevel::none; // unknown error
}
std::string StorageErrorBlock::format_lifetime_hours() const
{
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << lifetime_hours;
return ss.str();
}
std::ostream& operator<< (std::ostream& os, const StorageErrorBlock& b)
{
os << "Error number " << b.error_num << ": "
<< hz::string_join(b.reported_types, ", ")
<< " [" << StorageErrorBlock::get_displayable_error_types(b.reported_types) << "]";
return os;
}
std::string StorageSelftestEntry::format_lifetime_hours() const
{
std::stringstream ss;
try {
ss.imbue(std::locale(""));
}
catch (const std::runtime_error& e) {
// something is wrong with system locale, can't do anything here.
}
ss << std::fixed << lifetime_hours;
return ss.str();
}
std::ostream& operator<< (std::ostream& os, const StorageSelftestEntry& b)
{
os << "Test entry " << b.test_num << ": "
<< b.type << ", status: " << b.get_status_str() << ", remaining: " << int(b.remaining_percent);
return os;
}
void StorageProperty::dump(std::ostream& os, std::size_t internal_offset) const
{
std::string offset(internal_offset, ' ');
os << offset << "[" << get_section_name(section)
<< (section == Section::data ? (", " + get_subsection_name(subsection)) : "") << "]"
<< " " << generic_name
// << (generic_name == reported_name ? "" : (" (" + reported_name + ")"))
<< ": [" << get_value_type_name() << "] ";
// if (!readable_value.empty())
// os << readable_value;
if (std::holds_alternative<std::monostate>(value)) {
os << "[empty]";
} else if (std::holds_alternative<std::string>(value)) {
os << std::get<std::string>(value);
} else if (std::holds_alternative<int64_t>(value)) {
os << std::get<int64_t>(value) << " [" << reported_value << "]";
} else if (std::holds_alternative<bool>(value)) {
os << std::string(std::get<bool>(value) ? "Yes" : "No") << " [" << reported_value << "]";
} else if (std::holds_alternative<std::chrono::seconds>(value)) {
os << std::get<std::chrono::seconds>(value).count() << " sec [" << reported_value << "]";
} else if (std::holds_alternative<StorageCapability>(value)) {
os << std::get<StorageCapability>(value);
} else if (std::holds_alternative<StorageAttribute>(value)) {
os << std::get<StorageAttribute>(value);
} else if (std::holds_alternative<StorageStatistic>(value)) {
os << std::get<StorageStatistic>(value);
} else if (std::holds_alternative<StorageErrorBlock>(value)) {
os << std::get<StorageErrorBlock>(value);
} else if (std::holds_alternative<StorageSelftestEntry>(value)) {
os << std::get<StorageSelftestEntry>(value);
}
}
std::string StorageProperty::format_value(bool add_reported_too) const
{
if (!readable_value.empty())
return readable_value;
if (std::holds_alternative<std::monostate>(value))
return "[unknown]";
if (std::holds_alternative<std::string>(value))
return std::get<std::string>(value);
if (std::holds_alternative<int64_t>(value))
return hz::number_to_string_locale(std::get<int64_t>(value)) + (add_reported_too ? (" [" + reported_value + "]") : "");
if (std::holds_alternative<bool>(value))
return std::string(std::get<bool>(value) ? "Yes" : "No") + (add_reported_too ? (" [" + reported_value + "]") : "");
if (std::holds_alternative<std::chrono::seconds>(value))
return hz::format_time_length(std::get<std::chrono::seconds>(value)) + (add_reported_too ? (" [" + reported_value + "]") : "");
if (std::holds_alternative<StorageCapability>(value))
return hz::stream_cast<std::string>(std::get<StorageCapability>(value));
if (std::holds_alternative<StorageAttribute>(value))
return hz::stream_cast<std::string>(std::get<StorageAttribute>(value));
if (std::holds_alternative<StorageStatistic>(value))
return hz::stream_cast<std::string>(std::get<StorageStatistic>(value));
if (std::holds_alternative<StorageErrorBlock>(value))
return hz::stream_cast<std::string>(std::get<StorageErrorBlock>(value));
if (std::holds_alternative<StorageSelftestEntry>(value))
return hz::stream_cast<std::string>(std::get<StorageSelftestEntry>(value));
return "[internal_error]";
}
/// @}
@@ -9,12 +9,12 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef STORAGE_PROPERTY_COLORS_H
#define STORAGE_PROPERTY_COLORS_H
#ifndef WARNING_COLORS_H
#define WARNING_COLORS_H
#include "local_glibmm.h"
#include "storage_property.h"
#include "ata_storage_property.h"
@@ -62,7 +62,7 @@ inline bool app_property_get_label_highlight_color(WarningLevel warning, std::st
/// Format warning text, but without description
inline std::string storage_property_get_warning_reason(const StorageProperty& p)
inline std::string storage_property_get_warning_reason(const AtaStorageProperty& p)
{
std::string fg, start = "<b>", stop = "</b>";
if (app_property_get_label_highlight_color(p.warning, fg)) {
@@ -70,17 +70,19 @@ inline std::string storage_property_get_warning_reason(const StorageProperty& p)
stop = "</span>" + stop;
}
if (p.warning == WarningLevel::notice) {
/// Translators: %1 and %2 are HTML tags, %3 is a message.
return Glib::ustring::compose(_("%1Notice:%2 %3"), start, stop, p.warning_reason);
} else if (p.warning == WarningLevel::warning) {
/// Translators: %1 and %2 are HTML tags, %3 is a message.
return Glib::ustring::compose(_("%1Warning:%2 %3"), start, stop, p.warning_reason);
} else if (p.warning == WarningLevel::alert) {
/// Translators: %1 and %2 are HTML tags, %3 is a message.
return Glib::ustring::compose(_("%1ALERT:%2 %3"), start, stop, p.warning_reason);
switch (p.warning) {
case WarningLevel::none:
// nothing
break;
case WarningLevel::notice:
/// Translators: %1 and %2 are HTML tags, %3 is a message.
return Glib::ustring::compose(_("%1Notice:%2 %3"), start, stop, p.warning_reason);
case WarningLevel::warning:
/// Translators: %1 and %2 are HTML tags, %3 is a message.
return Glib::ustring::compose(_("%1Warning:%2 %3"), start, stop, p.warning_reason);
case WarningLevel::alert:
/// Translators: %1 and %2 are HTML tags, %3 is a message.
return Glib::ustring::compose(_("%1ALERT:%2 %3"), start, stop, p.warning_reason);
}
return std::string();
@@ -90,7 +92,7 @@ inline std::string storage_property_get_warning_reason(const StorageProperty& p)
/// Append warning text to description and set it on the property
inline void storage_property_autoset_warning_descr(StorageProperty& p)
inline void storage_property_autoset_warning_descr(AtaStorageProperty& p)
{
std::string reason = storage_property_get_warning_reason(p);
p.set_description(p.get_description() + (reason.empty() ? "" : "\n\n" + reason));
-1
View File
@@ -15,7 +15,6 @@ Copyright:
#include "hz/string_algo.h" // hz::string_*
#include "hz/launch_url.h"
#include "hz/data_file.h"
#include "applib/app_gtkmm_features.h"
#include "gsc_about_dialog.h"
+1 -1
View File
@@ -15,7 +15,7 @@ Copyright:
#include "hz/fs_ns.h"
#include "hz/string_sprintf.h"
#include "applib/app_gtkmm_utils.h"
#include "applib/app_gtkmm_tools.h"
#include "gsc_add_device_window.h"
#include "gsc_main_window.h"
+1 -2
View File
@@ -16,8 +16,7 @@ Copyright:
#include <cstddef> // std::size_t
#include <memory>
#include "applib/app_gtkmm_utils.h" // app_gtkmm_create_tree_view_column
#include "applib/app_gtkmm_features.h"
#include "applib/app_gtkmm_tools.h" // app_gtkmm_create_tree_view_column
#include "hz/fs.h"
#include "rconfig/rconfig.h"
+68 -68
View File
@@ -23,8 +23,8 @@ Copyright:
#include "hz/format_unit.h" // format_time_length
#include "rconfig/rconfig.h" // rconfig::*
#include "applib/app_gtkmm_utils.h" // app_gtkmm_*
#include "applib/storage_property_colors.h"
#include "applib/app_gtkmm_tools.h" // app_gtkmm_*
#include "applib/warning_colors.h"
#include "applib/gui_utils.h" // gui_show_error_dialog
#include "applib/smartctl_executor_gui.h"
@@ -39,15 +39,15 @@ using namespace std::literals;
/// A label for StorageProperty
/// A label for AtaStorageProperty
struct PropertyLabel {
/// Constructor
PropertyLabel(std::string label_, const StorageProperty* prop, bool markup_ = false) :
PropertyLabel(std::string label_, const AtaStorageProperty* prop, bool markup_ = false) :
label(std::move(label_)), property(prop), markup(markup_)
{ }
std::string label; ///< Label text
const StorageProperty* property = nullptr; ///< Storage property
const AtaStorageProperty* property = nullptr; ///< Storage property
bool markup = false; ///< Whether the label text uses markup
};
@@ -114,9 +114,9 @@ namespace {
/// Cell renderer functions for list cells
inline void app_list_cell_renderer_func(Gtk::CellRenderer* cr, const Gtk::TreeModel::iterator& iter,
Gtk::TreeModelColumn<const StorageProperty*> storage_column)
Gtk::TreeModelColumn<const AtaStorageProperty*> storage_column)
{
const StorageProperty* p = (*iter)[storage_column];
const AtaStorageProperty* p = (*iter)[storage_column];
if (auto* crt = dynamic_cast<Gtk::CellRendererText*>(cr)) {
std::string fg, bg;
if (app_property_get_row_highlight_colors(p->warning, fg, bg)) {
@@ -130,7 +130,7 @@ namespace {
crt->property_cell_background().reset_value();
crt->property_foreground().reset_value();
}
if (p->is_value_type<StorageStatistic>() && p->get_value<StorageStatistic>().is_header) {
if (p->is_value_type<AtaStorageStatistic>() && p->get_value<AtaStorageStatistic>().is_header) {
crt->property_weight() = Pango::WEIGHT_BOLD;
} else {
crt->property_weight().reset_value();
@@ -358,7 +358,7 @@ void GscInfoWindow::set_drive(StorageDevicePtr d)
if (drive) // if an old drive is present, disconnect our callback from it.
drive_changed_connection.disconnect();
drive = std::move(d);
drive_changed_connection = drive->signal_changed.connect(sigc::mem_fun(this,
drive_changed_connection = drive->signal_changed().connect(sigc::mem_fun(this,
&GscInfoWindow::on_drive_changed));
}
@@ -867,13 +867,13 @@ void GscInfoWindow::on_test_type_combo_changed()
void GscInfoWindow::fill_ui_general(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_general(const std::vector<AtaStorageProperty>& props)
{
// filter out some properties
std::vector<StorageProperty> id_props, version_props, health_props;
std::vector<AtaStorageProperty> id_props, version_props, health_props;
for (auto&& p : props) {
if (p.section == StorageProperty::Section::info) {
if (p.section == AtaStorageProperty::Section::info) {
if (p.generic_name == "smartctl_version_full") {
version_props.push_back(p);
} else if (p.generic_name == "smartctl_version") {
@@ -881,7 +881,7 @@ void GscInfoWindow::fill_ui_general(const std::vector<StorageProperty>& props)
} else {
id_props.push_back(p);
}
} else if (p.section == StorageProperty::Section::data && p.subsection == StorageProperty::SubSection::health) {
} else if (p.section == AtaStorageProperty::Section::data && p.subsection == AtaStorageProperty::SubSection::health) {
health_props.push_back(p);
}
}
@@ -958,7 +958,7 @@ void GscInfoWindow::fill_ui_general(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_attributes(const std::vector<AtaStorageProperty>& props)
{
auto* treeview = lookup_widget<Gtk::TreeView*>("attributes_treeview");
@@ -1035,7 +1035,7 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
treeview->set_tooltip_column(col_tooltip.index());
Gtk::TreeModelColumn<const StorageProperty*> col_storage;
Gtk::TreeModelColumn<const AtaStorageProperty*> col_storage;
model_columns.add(col_storage);
@@ -1055,11 +1055,11 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
std::vector<PropertyLabel> label_strings; // outside-of-tree properties
for (const auto& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::attributes)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::attributes)
continue;
// add non-attribute-type properties to label above
if (!p.is_value_type<StorageAttribute>()) {
if (!p.is_value_type<AtaStorageAttribute>()) {
label_strings.emplace_back(p.displayable_name + ": " + p.format_value(), &p);
if (int(p.warning) > int(max_tab_warning))
@@ -1067,14 +1067,14 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
continue;
}
const auto& attr = p.get_value<StorageAttribute>();
const auto& attr = p.get_value<AtaStorageAttribute>();
std::string attr_type = StorageAttribute::get_attr_type_name(attr.attr_type);
if (attr.attr_type == StorageAttribute::AttributeType::prefail)
std::string attr_type = AtaStorageAttribute::get_attr_type_name(attr.attr_type);
if (attr.attr_type == AtaStorageAttribute::AttributeType::prefail)
attr_type.append("<b>").append(attr_type).append("</b>");
std::string fail_time = StorageAttribute::get_fail_time_name(attr.when_failed);
if (attr.when_failed != StorageAttribute::FailTime::none)
std::string fail_time = AtaStorageAttribute::get_fail_time_name(attr.when_failed);
if (attr.when_failed != AtaStorageAttribute::FailTime::none)
fail_time.append("<b>").append(fail_time).append("</b>");
Gtk::TreeRow row = *(list_store->append());
@@ -1087,7 +1087,7 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
row[col_threshold] = (attr.threshold.has_value() ? hz::number_to_string_locale(attr.threshold.value()) : "-");
row[col_raw] = attr.format_raw_value();
row[col_type] = attr_type;
// row[col_updated] = StorageAttribute::get_update_type_name(attr.update_type);
// row[col_updated] = AtaStorageAttribute::get_update_type_name(attr.update_type);
row[col_failed] = fail_time;
row[col_tooltip] = p.get_description();
row[col_storage] = &p;
@@ -1106,7 +1106,7 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_statistics(const std::vector<AtaStorageProperty>& props)
{
auto* treeview = lookup_widget<Gtk::TreeView*>("statistics_treeview");
@@ -1145,7 +1145,7 @@ void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props
model_columns.add(col_tooltip);
treeview->set_tooltip_column(col_tooltip.index());
Gtk::TreeModelColumn<const StorageProperty*> col_storage;
Gtk::TreeModelColumn<const AtaStorageProperty*> col_storage;
model_columns.add(col_storage);
@@ -1164,11 +1164,11 @@ void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props
std::vector<PropertyLabel> label_strings; // outside-of-tree properties
for (const auto& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::devstat)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::devstat)
continue;
// add non-entry-type properties to label above
if (!p.is_value_type<StorageStatistic>()) {
if (!p.is_value_type<AtaStorageStatistic>()) {
label_strings.emplace_back(p.displayable_name + ": " + p.format_value(), &p);
if (int(p.warning) > int(max_tab_warning))
@@ -1178,7 +1178,7 @@ void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props
Gtk::TreeRow row = *(list_store->append());
const auto& st = p.get_value<StorageStatistic>();
const auto& st = p.get_value<AtaStorageStatistic>();
row[col_description] = (st.is_header ? p.displayable_name : (" " + p.displayable_name));
row[col_value] = st.format_value();
row[col_flags] = st.flags; // it's a string, not int.
@@ -1286,7 +1286,7 @@ void GscInfoWindow::fill_ui_self_test_info()
void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_self_test_log(const std::vector<AtaStorageProperty>& props)
{
auto* treeview = lookup_widget<Gtk::TreeView*>("selftest_log_treeview");
@@ -1333,7 +1333,7 @@ void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& pr
model_columns.add(col_tooltip);
treeview->set_tooltip_column(col_tooltip.index());
Gtk::TreeModelColumn<const StorageProperty*> col_storage;
Gtk::TreeModelColumn<const AtaStorageProperty*> col_storage;
model_columns.add(col_storage);
@@ -1353,14 +1353,14 @@ void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& pr
std::vector<PropertyLabel> label_strings; // outside-of-tree properties
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::selftest_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::selftest_log)
continue;
if (p.generic_name == "selftest_log") // the whole section, we don't need it
continue;
// add non-entry properties to label above
if (!p.is_value_type<StorageSelftestEntry>()) {
if (!p.is_value_type<AtaStorageSelftestEntry>()) {
label_strings.emplace_back(p.displayable_name + ": " + p.format_value(), &p);
if (int(p.warning) > int(max_tab_warning))
@@ -1370,7 +1370,7 @@ void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& pr
Gtk::TreeRow row = *(list_store->append());
const auto& sse = p.get_value<StorageSelftestEntry>();
const auto& sse = p.get_value<AtaStorageSelftestEntry>();
row[col_num] = sse.test_num;
row[col_type] = sse.type;
@@ -1397,7 +1397,7 @@ void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& pr
void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_error_log(const std::vector<AtaStorageProperty>& props)
{
auto* treeview = lookup_widget<Gtk::TreeView*>("error_log_treeview");
@@ -1437,7 +1437,7 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
model_columns.add(col_tooltip);
treeview->set_tooltip_column(col_tooltip.index());
Gtk::TreeModelColumn<const StorageProperty*> col_storage;
Gtk::TreeModelColumn<const AtaStorageProperty*> col_storage;
model_columns.add(col_storage);
Gtk::TreeModelColumn<Glib::ustring> col_mark_name;
@@ -1460,7 +1460,7 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
std::vector<PropertyLabel> label_strings; // outside-of-tree properties
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::error_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::error_log)
continue;
// Note: Don't use property description as a tooltip here. It won't be available if there's no property.
@@ -1494,13 +1494,13 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
// add non-tree properties to label above
} else if (!p.is_value_type<StorageErrorBlock>()) {
} else if (!p.is_value_type<AtaStorageErrorBlock>()) {
label_strings.emplace_back(p.displayable_name + ": " + p.format_value(), &p);
if (p.generic_name == "error_log_error_count")
label_strings.back().label += " "s + _("(Note: The number of entries may be limited to the newest ones)");
} else {
const auto& eb = p.get_value<StorageErrorBlock>();
const auto& eb = p.get_value<AtaStorageErrorBlock>();
std::string type_details = eb.type_more_info;
@@ -1508,7 +1508,7 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
row[col_num] = eb.error_num;
row[col_hours] = eb.format_lifetime_hours();
row[col_state] = eb.device_state;
row[col_type] = StorageErrorBlock::get_displayable_error_types(eb.reported_types);
row[col_type] = AtaStorageErrorBlock::get_displayable_error_types(eb.reported_types);
row[col_details] = (type_details.empty() ? "-" : type_details); // e.g. OBS has no details
// There are no descriptions in self-test log entries, so don't display
// "No description available" for all of them.
@@ -1530,7 +1530,7 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_temperature_log(const std::vector<StorageProperty>& props)
void GscInfoWindow::fill_ui_temperature_log(const std::vector<AtaStorageProperty>& props)
{
auto* textview = lookup_widget<Gtk::TextView*>("temperature_log_textview");
@@ -1538,7 +1538,7 @@ void GscInfoWindow::fill_ui_temperature_log(const std::vector<StorageProperty>&
std::vector<PropertyLabel> label_strings; // outside-of-tree properties
std::string temperature;
StorageProperty temp_property;
AtaStorageProperty temp_property;
enum { temp_attr2 = 1, temp_attr1, temp_stat, temp_sct }; // less important to more important
int temp_prop_source = 0;
@@ -1550,22 +1550,22 @@ void GscInfoWindow::fill_ui_temperature_log(const std::vector<StorageProperty>&
temp_prop_source = temp_sct;
}
if (temp_prop_source < temp_stat && p.generic_name == "stat_temperature_celsius") {
temperature = hz::number_to_string_locale(p.get_value<StorageStatistic>().value_int);
temperature = hz::number_to_string_locale(p.get_value<AtaStorageStatistic>().value_int);
temp_property = p;
temp_prop_source = temp_stat;
}
if (temp_prop_source < temp_attr1 && p.generic_name == "attr_temperature_celsius") {
temperature = hz::number_to_string_locale(p.get_value<StorageAttribute>().raw_value_int);
temperature = hz::number_to_string_locale(p.get_value<AtaStorageAttribute>().raw_value_int);
temp_property = p;
temp_prop_source = temp_attr1;
}
if (temp_prop_source < temp_attr2 && p.generic_name == "attr_temperature_celsius_x10") {
temperature = hz::number_to_string_locale(p.get_value<StorageAttribute>().raw_value_int / 10);
temperature = hz::number_to_string_locale(p.get_value<AtaStorageAttribute>().raw_value_int / 10);
temp_property = p;
temp_prop_source = temp_attr2;
}
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::temperature_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::temperature_log)
continue;
if (p.generic_name == "sct_unsupported" && p.get_value<bool>()) { // only show if unsupported
@@ -1602,7 +1602,7 @@ void GscInfoWindow::fill_ui_temperature_log(const std::vector<StorageProperty>&
WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<StorageProperty>& props)
WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<AtaStorageProperty>& props)
{
auto* treeview = lookup_widget<Gtk::TreeView*>("capabilities_treeview");
@@ -1635,7 +1635,7 @@ WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<StorageProper
model_columns.add(col_tooltip);
treeview->set_tooltip_column(col_tooltip.index());
Gtk::TreeModelColumn<const StorageProperty*> col_storage;
Gtk::TreeModelColumn<const AtaStorageProperty*> col_storage;
model_columns.add(col_storage);
@@ -1655,16 +1655,16 @@ WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<StorageProper
int index = 1;
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::capabilities)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::capabilities)
continue;
Glib::ustring name = p.displayable_name;
std::string flag_value;
Glib::ustring str_value;
if (p.is_value_type<StorageCapability>()) {
flag_value = hz::number_to_string_nolocale(p.get_value<StorageCapability>().flag_value, 16); // 0xXX
str_value = hz::string_join(p.get_value<StorageCapability>().strvalues, "\n");
if (p.is_value_type<AtaStorageCapability>()) {
flag_value = hz::number_to_string_nolocale(p.get_value<AtaStorageCapability>().flag_value, 16); // 0xXX
str_value = hz::string_join(p.get_value<AtaStorageCapability>().strvalues, "\n");
} else {
// no flag value here
str_value = p.format_value();
@@ -1692,14 +1692,14 @@ WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<StorageProper
WarningLevel GscInfoWindow::fill_ui_error_recovery(const std::vector<StorageProperty>& props)
WarningLevel GscInfoWindow::fill_ui_error_recovery(const std::vector<AtaStorageProperty>& props)
{
auto* textview = lookup_widget<Gtk::TextView*>("erc_log_textview");
WarningLevel max_tab_warning = WarningLevel::none;
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::erc_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::erc_log)
continue;
// Note: Don't use property description as a tooltip here. It won't be available if there's no property.
@@ -1717,14 +1717,14 @@ WarningLevel GscInfoWindow::fill_ui_error_recovery(const std::vector<StorageProp
WarningLevel GscInfoWindow::fill_ui_selective_self_test_log(const std::vector<StorageProperty>& props)
WarningLevel GscInfoWindow::fill_ui_selective_self_test_log(const std::vector<AtaStorageProperty>& props)
{
auto* textview = lookup_widget<Gtk::TextView*>("selective_selftest_log_textview");
WarningLevel max_tab_warning = WarningLevel::none;
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::selective_selftest_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::selective_selftest_log)
continue;
// Note: Don't use property description as a tooltip here. It won't be available if there's no property.
@@ -1742,14 +1742,14 @@ WarningLevel GscInfoWindow::fill_ui_selective_self_test_log(const std::vector<St
WarningLevel GscInfoWindow::fill_ui_physical(const std::vector<StorageProperty>& props)
WarningLevel GscInfoWindow::fill_ui_physical(const std::vector<AtaStorageProperty>& props)
{
auto* textview = lookup_widget<Gtk::TextView*>("phy_log_textview");
WarningLevel max_tab_warning = WarningLevel::none;
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::phy_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::phy_log)
continue;
// Note: Don't use property description as a tooltip here. It won't be available if there's no property.
@@ -1767,14 +1767,14 @@ WarningLevel GscInfoWindow::fill_ui_physical(const std::vector<StorageProperty>&
WarningLevel GscInfoWindow::fill_ui_directory(const std::vector<StorageProperty>& props)
WarningLevel GscInfoWindow::fill_ui_directory(const std::vector<AtaStorageProperty>& props)
{
auto* textview = lookup_widget<Gtk::TextView*>("directory_log_textview");
WarningLevel max_tab_warning = WarningLevel::none;
for (auto&& p : props) {
if (p.section != StorageProperty::Section::data || p.subsection != StorageProperty::SubSection::directory_log)
if (p.section != AtaStorageProperty::Section::data || p.subsection != AtaStorageProperty::SubSection::directory_log)
continue;
// Note: Don't use property description as a tooltip here. It won't be available if there's no property.
@@ -1891,25 +1891,25 @@ gboolean GscInfoWindow::test_idle_callback(void* data)
self->test_timer_poll.stop(); // just in case
self->test_timer_bar.stop(); // just in case
StorageSelftestEntry::Status status = self->current_test->get_status();
AtaStorageSelftestEntry::Status status = self->current_test->get_status();
bool aborted = false;
StorageSelftestEntry::StatusSeverity severity = StorageSelftestEntry::StatusSeverity::none;
AtaStorageSelftestEntry::StatusSeverity severity = AtaStorageSelftestEntry::StatusSeverity::none;
std::string result_msg;
if (!self->test_error_msg.empty()) {
aborted = true;
severity = StorageSelftestEntry::StatusSeverity::error;
severity = AtaStorageSelftestEntry::StatusSeverity::error;
result_msg = Glib::ustring::compose(_("<b>Test aborted:</b> %1"), self->test_error_msg);
} else {
severity = StorageSelftestEntry::get_status_severity(status);
if (status == StorageSelftestEntry::Status::aborted_by_host) {
severity = AtaStorageSelftestEntry::get_status_severity(status);
if (status == AtaStorageSelftestEntry::Status::aborted_by_host) {
aborted = true;
result_msg = "<b>"s + _("Test was manually aborted.") + "</b>"; // it's a StatusSeverity::none message
} else {
result_msg = Glib::ustring::compose(_("<b>Test result:</b> %1."), StorageSelftestEntry::get_status_displayable_name(status));
result_msg = Glib::ustring::compose(_("<b>Test result:</b> %1."), AtaStorageSelftestEntry::get_status_displayable_name(status));
// It may not reach 100% somehow, so do it manually.
if (test_completion_progressbar)
@@ -1917,7 +1917,7 @@ gboolean GscInfoWindow::test_idle_callback(void* data)
}
}
if (severity != StorageSelftestEntry::StatusSeverity::none) {
if (severity != AtaStorageSelftestEntry::StatusSeverity::none) {
result_msg += "\n"s + _("Check the Self-Test Log for more information.");
}
@@ -1935,9 +1935,9 @@ gboolean GscInfoWindow::test_idle_callback(void* data)
test_stop_button->set_sensitive(false);
Gtk::StockID stock_id = Gtk::Stock::DIALOG_ERROR;
if (severity == StorageSelftestEntry::StatusSeverity::none) {
if (severity == AtaStorageSelftestEntry::StatusSeverity::none) {
stock_id = Gtk::Stock::DIALOG_INFO;
} else if (severity == StorageSelftestEntry::StatusSeverity::warning) {
} else if (severity == AtaStorageSelftestEntry::StatusSeverity::warning) {
stock_id = Gtk::Stock::DIALOG_WARNING;
}
+11 -11
View File
@@ -58,40 +58,40 @@ class GscInfoWindow : public AppBuilderWidget<GscInfoWindow, true> {
protected:
/// fill_ui_with_info() helper
void fill_ui_general(const std::vector<StorageProperty>& props);
void fill_ui_general(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
void fill_ui_attributes(const std::vector<StorageProperty>& props);
void fill_ui_attributes(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
void fill_ui_statistics(const std::vector<StorageProperty>& props);
void fill_ui_statistics(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
void fill_ui_self_test_info();
/// fill_ui_with_info() helper
void fill_ui_self_test_log(const std::vector<StorageProperty>& props);
void fill_ui_self_test_log(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
void fill_ui_error_log(const std::vector<StorageProperty>& props);
void fill_ui_error_log(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
void fill_ui_temperature_log(const std::vector<StorageProperty>& props);
void fill_ui_temperature_log(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
WarningLevel fill_ui_capabilities(const std::vector<StorageProperty>& props);
WarningLevel fill_ui_capabilities(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
WarningLevel fill_ui_error_recovery(const std::vector<StorageProperty>& props);
WarningLevel fill_ui_error_recovery(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
WarningLevel fill_ui_selective_self_test_log(const std::vector<StorageProperty>& props);
WarningLevel fill_ui_selective_self_test_log(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
WarningLevel fill_ui_physical(const std::vector<StorageProperty>& props);
WarningLevel fill_ui_physical(const std::vector<AtaStorageProperty>& props);
/// fill_ui_with_info() helper
WarningLevel fill_ui_directory(const std::vector<StorageProperty>& props);
WarningLevel fill_ui_directory(const std::vector<AtaStorageProperty>& props);
// -------------------- callbacks
+5 -5
View File
@@ -21,12 +21,12 @@ Copyright:
#include "hz/fs.h"
#include "rconfig/rconfig.h"
#include "applib/storage_detector.h"
#include "applib/smartctl_parser.h"
#include "applib/smartctl_text_parser.h"
#include "applib/gui_utils.h" // gui_show_error_dialog
#include "applib/smartctl_executor.h" // get_smartctl_binary()
#include "applib/smartctl_executor_gui.h"
#include "applib/app_gtkmm_utils.h" // app_gtkmm_*
#include "applib/storage_property_colors.h" // app_property_get_label_highlight_color
#include "applib/app_gtkmm_tools.h" // app_gtkmm_*
#include "applib/warning_colors.h" // app_property_get_label_highlight_color
#include "applib/app_pcrecpp.h" // app_pcre_match
#include "gsc_init.h" // app_quit()
@@ -118,7 +118,7 @@ GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, Glib::RefPtr<Gtk::Builder>
}
std::string version, version_full;
if (!SmartctlParser::parse_version(output, version, version_full)) {
if (!SmartctlTextParser::parse_version(output, version, version_full)) {
error_msg = _("Smartctl returned invalid output.");
break;
}
@@ -941,7 +941,7 @@ void GscMainWindow::update_status_widgets()
app_gtkmm_set_widget_tooltip(*name_label_, info_str, false); // in case it doesn't fit
}
StorageProperty health_prop = drive->get_health_property();
AtaStorageProperty health_prop = drive->get_health_property();
if (health_label_) {
if (health_prop.generic_name == "overall_health") {
+5 -5
View File
@@ -22,8 +22,8 @@ Copyright:
#include "hz/string_algo.h" // string_join
#include "hz/debug.h"
#include "hz/data_file.h" // data_file_find
#include "applib/app_gtkmm_utils.h"
#include "applib/storage_property_colors.h"
#include "applib/app_gtkmm_tools.h"
#include "applib/warning_colors.h"
#include "gsc_main_window.h"
#include "rconfig/rconfig.h"
@@ -229,7 +229,7 @@ class GscMainWindowIconView : public Gtk::IconView {
this->decorate_entry(row);
drive->signal_changed.connect(sigc::mem_fun(this, &GscMainWindowIconView::on_drive_changed));
drive->signal_changed().connect(sigc::mem_fun(this, &GscMainWindowIconView::on_drive_changed));
if (scroll_to_it) {
Gtk::TreeModel::Path tpath(row);
@@ -296,7 +296,7 @@ class GscMainWindowIconView : public Gtk::IconView {
if (rconfig::get_data<bool>("gui/icons_show_serial_number") && !drive->get_serial_number().empty()) {
name += "\n" + Glib::Markup::escape_text(drive->get_serial_number());
}
StorageProperty scan_time_prop;
AtaStorageProperty scan_time_prop;
if (drive->get_is_virtual()) {
scan_time_prop = drive->lookup_property("scan_time");
if (!scan_time_prop.empty() && !scan_time_prop.get_value<std::string>().empty()) {
@@ -343,7 +343,7 @@ class GscMainWindowIconView : public Gtk::IconView {
break;
}
StorageProperty health_prop = drive->get_health_property();
AtaStorageProperty health_prop = drive->get_health_property();
if (health_prop.warning != WarningLevel::none && health_prop.generic_name == "overall_health") {
if (icon) {
icon = icon->copy(); // work on a copy
+1 -1
View File
@@ -21,7 +21,7 @@ Copyright:
#include "hz/string_sprintf.h"
#include "rconfig/rconfig.h"
#include "applib/storage_settings.h"
#include "applib/app_gtkmm_utils.h"
#include "applib/app_gtkmm_tools.h"
#include "gsc_main_window.h"
#include "gsc_preferences_window.h"
+1 -2
View File
@@ -22,9 +22,8 @@ Copyright:
#include "hz/fs.h"
#include "rconfig/rconfig.h"
#include "applib/app_gtkmm_features.h"
#include "applib/app_builder_widget.h"
#include "applib/app_gtkmm_utils.h"
#include "applib/app_gtkmm_tools.h"