mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-25 05:15:33 +00:00
Show Error Log and Self-Test Log support.
Support attributes with undefined values like "---".
This commit is contained in:
+3
-3
@@ -38,7 +38,9 @@ TODO:
|
||||
|
||||
Add debian/ubuntu's su-to-root support to gsmartcontrol-root.
|
||||
|
||||
Add support for parsing SSD outputs.
|
||||
Add support for SSD smartctl attribute names (they're totally different).
|
||||
Check smartctl sources, they print those names.
|
||||
|
||||
|
||||
Testing:
|
||||
If ETA time has elapsed, but it's still only at 10% completion,
|
||||
@@ -105,8 +107,6 @@ Monitor:
|
||||
Periodically see if drives were added / removed (possibly use OS callbacks
|
||||
instead of polling?)
|
||||
|
||||
Fix inability to detect types in some error logs.
|
||||
|
||||
Options->Prefs->Drives
|
||||
Add a hint about "pd0" for Windows version.
|
||||
|
||||
|
||||
@@ -997,16 +997,23 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
// named "Head flying hours". So, parse until we encounter the next column.
|
||||
// * One WD drive had non-integer flags, something like "PO--C-", with several
|
||||
// lines of their descriptions after the attributes block (each line started with spaces and |).
|
||||
// * SSD drives may show "---" in value/worst/threshold fields.
|
||||
|
||||
// " 1 Raw_Read_Error_Rate 0x000f 115 099 006 Pre-fail Always - 90981479"
|
||||
// " 12 Power_Cycle_Count 0x0000 --- --- --- Old_age Offline - 167"
|
||||
|
||||
bool attr_found = false; // at least one attribute was found
|
||||
bool attr_format_with_updated = false; // UPDATED column present
|
||||
|
||||
pcrecpp::RE re_up = app_pcre_re("/[ \\t]*([0-9]+) ([^\\t\\n]+)[ \\t]+((?:0x[a-fA-F0-9]+)|(?:[A-Z-]{2,}))[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+"
|
||||
"([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+(.+)[ \\t]*/mi");
|
||||
std::string base_re = "[ \\t]*([0-9]+) ([^\\t\\n]+)[ \\t]+((?:0x[a-fA-F0-9]+)|(?:[A-Z-]{2,}))[ \\t]+" // name / flag
|
||||
"([0-9-]+)[ \\t]+([0-9-]+)[ \\t]+([0-9-]+)[ \\t]+" // value / worst / threshold
|
||||
"([^ \\t\\n]+)[ \\t]+"; // type
|
||||
|
||||
pcrecpp::RE re_noup = app_pcre_re("/[ \\t]*([0-9]+) ([^\\t\\n]+)[ \\t]+((?:0x[a-fA-F0-9]+)|(?:[A-Z-]{2,}))[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+"
|
||||
"([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+(.+)[ \\t]*/mi");
|
||||
pcrecpp::RE re_up = app_pcre_re("/" + base_re
|
||||
+ "([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+(.+)[ \\t]*/mi"); // updated / when_failed / raw
|
||||
|
||||
pcrecpp::RE re_noup = app_pcre_re("/" + base_re
|
||||
+ "([^ \\t\\n]+)[ \\t]+(.+)[ \\t]*/mi"); // when_failed / raw
|
||||
|
||||
pcrecpp::RE re_flag_descr = app_pcre_re("/^[\\t ]+\\|/mi");
|
||||
|
||||
@@ -1080,9 +1087,17 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
StorageAttribute a;
|
||||
hz::string_is_numeric(hz::string_trim_copy(id), a.id, true, 10);
|
||||
a.flag = hz::string_trim_copy(flag);
|
||||
hz::string_is_numeric(hz::string_trim_copy(value), a.value, true, 10);
|
||||
hz::string_is_numeric(hz::string_trim_copy(worst), a.worst, true, 10);
|
||||
hz::string_is_numeric(hz::string_trim_copy(threshold), a.threshold, true, 10);
|
||||
uint8_t norm_value = 0, worst_value = 0, threshold_value = 0;
|
||||
|
||||
if (hz::string_is_numeric(hz::string_trim_copy(value), norm_value, true, 10)) {
|
||||
a.value = norm_value;
|
||||
}
|
||||
if (hz::string_is_numeric(hz::string_trim_copy(worst), worst_value, true, 10)) {
|
||||
a.worst = worst_value;
|
||||
}
|
||||
if (hz::string_is_numeric(hz::string_trim_copy(threshold), threshold_value, true, 10)) {
|
||||
a.threshold = threshold_value;
|
||||
}
|
||||
|
||||
a.attr_type = (attr_type == "Pre-fail" ? StorageAttribute::attr_type_prefail
|
||||
: (attr_type == "Old_age" ? StorageAttribute::attr_type_oldage : StorageAttribute::attr_type_unknown));
|
||||
@@ -1139,7 +1154,7 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
|
||||
bool data_found = false;
|
||||
|
||||
// error log version
|
||||
// Error log version
|
||||
{
|
||||
pcrecpp::RE re = app_pcre_re("/^(SMART Error Log Version):[ \\t]*(.*)$/mi");
|
||||
|
||||
@@ -1162,7 +1177,20 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
// error log count
|
||||
// Error log support
|
||||
{
|
||||
pcrecpp::RE re = app_pcre_re("/^(Warning: device does not support Error Logging)$/mi");
|
||||
|
||||
if (re.PartialMatch(sub)) {
|
||||
StorageProperty p(pt);
|
||||
p.set_name("error_log_unsupported");
|
||||
p.readable_name = "Warning";
|
||||
p.readable_value = "Device does not support error logging";
|
||||
add_property(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Error log enty count
|
||||
{
|
||||
// note: these represent the same information
|
||||
pcrecpp::RE re1 = app_pcre_re("/^ATA Error Count:[ \\t]*([0-9]+)/mi");
|
||||
@@ -1279,7 +1307,7 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
|
||||
bool data_found = false; // true if something was found.
|
||||
|
||||
// the whole subsection
|
||||
// The whole subsection
|
||||
{
|
||||
StorageProperty p(pt);
|
||||
p.set_name("SMART Self-test log", "selftest_log");
|
||||
@@ -1292,7 +1320,20 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
}
|
||||
|
||||
|
||||
// self-test log version
|
||||
// Self-test log support
|
||||
{
|
||||
pcrecpp::RE re = app_pcre_re("/^(Warning: device does not support Self Test Logging)$/mi");
|
||||
|
||||
if (re.PartialMatch(sub)) {
|
||||
StorageProperty p(pt);
|
||||
p.set_name("selftest_log_unsupported");
|
||||
p.readable_name = "Warning";
|
||||
p.readable_value = "Device does not support self-test logging";
|
||||
add_property(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Self-test log version
|
||||
{
|
||||
// newer smartctl (since smartctl 5.1-16)
|
||||
pcrecpp::RE re1 = app_pcre_re("/(SMART Self-test log structure[^\\n0-9]*)([^ \\n]+)[ \\t]*$/mi");
|
||||
|
||||
@@ -31,9 +31,13 @@ std::ostream& operator<< (std::ostream& os, const StorageCapability& p)
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const StorageAttribute& p)
|
||||
{
|
||||
os
|
||||
// << p.name << ": "
|
||||
<< static_cast<int>(p.value) << " (" << p.raw_value_int << ")";
|
||||
// os << p.name << ": "
|
||||
if (p.value.defined()) {
|
||||
os << static_cast<int>(p.value.value());
|
||||
} else {
|
||||
os << "-";
|
||||
}
|
||||
os << " (" << p.raw_value_int << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
|
||||
#include "hz/optional_value.h"
|
||||
#include "hz/cstdint.h"
|
||||
|
||||
|
||||
@@ -96,22 +97,21 @@ class StorageAttribute {
|
||||
}
|
||||
|
||||
|
||||
StorageAttribute() : id(-1), value(0), worst(0), threshold(0),
|
||||
attr_type(attr_type_unknown), update_type(update_type_unknown),
|
||||
StorageAttribute() : id(-1), attr_type(attr_type_unknown), update_type(update_type_unknown),
|
||||
when_failed(fail_time_unknown), raw_value_int(0)
|
||||
{ }
|
||||
|
||||
|
||||
int32_t id;
|
||||
std::string flag; // some have it in 0xXXXX format, others in "PO--C-" format (some WD drives?).
|
||||
uint8_t value;
|
||||
uint8_t worst;
|
||||
uint8_t threshold;
|
||||
int32_t id; ///< Attribute ID (most vendors agree on this)
|
||||
std::string flag; ///< Some have it in 0xXXXX format, others in "PO--C-" format (some WD drives?).
|
||||
hz::OptionalValue<uint8_t> value; ///< Normalized value. May be unset ("---").
|
||||
hz::OptionalValue<uint8_t> worst; ///< Worst ever value. May be unset ("---").
|
||||
hz::OptionalValue<uint8_t> threshold; ///< Threshold for normalized value. May be unset ("---").
|
||||
attr_t attr_type;
|
||||
update_t update_type;
|
||||
fail_time_t when_failed;
|
||||
std::string raw_value; // as presented by smartctl (formatted).
|
||||
int64_t raw_value_int; // same as raw_value, but parsed as int. original value is 6 bytes I think.
|
||||
std::string raw_value; ///< as presented by smartctl (formatted).
|
||||
int64_t raw_value_int; ///< same as raw_value, but parsed as int. original value is 6 bytes I think.
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -106,7 +106,6 @@ bool storage_property_autoset_description(StorageProperty& p)
|
||||
p.set_description("Checksum errors indicate that SMART data is invalid. This shouldn't happen in normal circumstances.");
|
||||
found = true;
|
||||
|
||||
|
||||
// Section Info
|
||||
} else if (p.section == StorageProperty::section_info) {
|
||||
found = auto_set(p, "Serial Number", "Serial number, unique to each physical drive.")
|
||||
@@ -265,10 +264,12 @@ bool storage_property_autoset_description(StorageProperty& p)
|
||||
} else if (p.section == StorageProperty::section_data && p.subsection == StorageProperty::subsection_error_log) {
|
||||
found = auto_set(p, "error_count", "Number of errors in error log. Note: Some manufacturers may list completely harmless errors in this log "
|
||||
"(e.g., command invalid, not implemented, etc...).");
|
||||
// || auto_set(p, "error_log_unsupported", "This device does not support error logging."); // the property text already says that
|
||||
|
||||
|
||||
} else if (p.section == StorageProperty::section_data && p.subsection == StorageProperty::subsection_selftest_log) {
|
||||
found = auto_set(p, "selftest_num_entries", "Number of tests in selftest log. Note: This log usually contains only the last 20 or so manual tests. ");
|
||||
// || auto_set(p, "selftest_log_unsupported", "This device does not support self-test logging."); // the property text already says that
|
||||
|
||||
} else if (p.section == StorageProperty::section_data && p.subsection == StorageProperty::subsection_selective_selftest_log) {
|
||||
// nothing here
|
||||
@@ -388,6 +389,10 @@ StorageProperty::warning_t storage_property_autoset_warning(StorageProperty& p)
|
||||
w = StorageProperty::warning_warn;
|
||||
reason = "The drive is reporting internal errors. Usually this means uncorrectable data loss and similar severe errors. "
|
||||
"Check the actual errors for details.";
|
||||
|
||||
} else if (name_match(p, "error_log_unsupported")) {
|
||||
w = StorageProperty::warning_notice;
|
||||
reason = "The drive does not support error logging. This means that SMART error history is unavailable.";
|
||||
}
|
||||
|
||||
|
||||
@@ -395,6 +400,11 @@ StorageProperty::warning_t storage_property_autoset_warning(StorageProperty& p)
|
||||
// don't include selftest warnings - they may be old or something.
|
||||
// self-tests are carried manually anyway, so the user is expected to check their status anyway.
|
||||
|
||||
if (name_match(p, "selftest_log_unsupported")) {
|
||||
w = StorageProperty::warning_notice;
|
||||
reason = "The drive does not support self-test logging. This means that SMART test results won't be logged.";
|
||||
}
|
||||
|
||||
} else if (p.section == StorageProperty::section_data && p.subsection == StorageProperty::subsection_selective_selftest_log) {
|
||||
// nothing here
|
||||
|
||||
|
||||
@@ -659,9 +659,9 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
|
||||
row[col_id] = iter->value_attribute.id;
|
||||
row[col_name] = iter->readable_name;
|
||||
row[col_flag_value] = iter->value_attribute.flag; // it's a string, not int.
|
||||
row[col_value] = hz::number_to_string(iter->value_attribute.value);
|
||||
row[col_worst] = hz::number_to_string(iter->value_attribute.worst);
|
||||
row[col_threshold] = hz::number_to_string(iter->value_attribute.threshold);
|
||||
row[col_value] = (iter->value_attribute.value.defined() ? hz::number_to_string(iter->value_attribute.value.value()) : "-");
|
||||
row[col_worst] = (iter->value_attribute.worst.defined() ? hz::number_to_string(iter->value_attribute.worst.value()) : "-");
|
||||
row[col_threshold] = (iter->value_attribute.threshold.defined() ? hz::number_to_string(iter->value_attribute.threshold.value()) : "-");
|
||||
row[col_raw] = iter->value_attribute.raw_value;
|
||||
row[col_type] = attr_type;
|
||||
row[col_updated] = StorageAttribute::get_update_type_name(iter->value_attribute.update_type);
|
||||
|
||||
@@ -27,7 +27,7 @@ class OptionalValue {
|
||||
typedef T value_type;
|
||||
|
||||
|
||||
OptionalValue() : value_(), defined_(true)
|
||||
OptionalValue() : value_(), defined_(false)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user