From 9f85d097360dbd118a1cbc95c21fb6e8620aa024 Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Fri, 14 Feb 2025 13:48:30 +0400 Subject: [PATCH] Support standard (non-extended) self-test log in JSON ATA parser (#79). --- src/applib/smartctl_json_ata_parser.cpp | 29 +++++++++++++++---------- src/applib/storage_property_descr.cpp | 4 +++- src/gui/gsc_info_window.cpp | 4 +++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/applib/smartctl_json_ata_parser.cpp b/src/applib/smartctl_json_ata_parser.cpp index 1af3bc9..f3d6a0c 100644 --- a/src/applib/smartctl_json_ata_parser.cpp +++ b/src/applib/smartctl_json_ata_parser.cpp @@ -548,6 +548,7 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_capab sse.status = status; sse.remaining_percent = -1; // unknown or n/a + // Present only when extended self-test log is supported if (auto remaining_percent_val = get_node_data(root_node, "ata_smart_data/self_test/status/remaining_percent"); remaining_percent_val.has_value()) { sse.remaining_percent = remaining_percent_val.value(); } @@ -562,6 +563,7 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_capab } }, + // Present only when extended self-test log is supported {"ata_smart_data/self_test/status/remaining_percent", _("Self-test remaining percentage"), integer_formatter("{} %")}, {"ata_smart_data/capabilities/self_tests_supported", _("Self-tests supported"), bool_formatter(_("Yes"), _("No"))}, @@ -890,12 +892,15 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft bool section_properties_found = false; + const bool extended = get_node_exists(json_root_node, "ata_smart_self_test_log/extended/revision").value_or(false); + const std::string log_key = extended ? "ata_smart_self_test_log/extended" : "ata_smart_self_test_log/standard"; + // Revision - if (get_node_exists(json_root_node, "ata_smart_self_test_log/extended/revision").value_or(false)) { + if (get_node_exists(json_root_node, log_key + "/revision").value_or(false)) { StorageProperty p; - p.set_name("ata_smart_self_test_log/extended/revision", _("SMART extended self-test log version")); + p.set_name(log_key + "/revision", extended ? _("SMART extended self-test log version") : _("SMART standard self-test log version")); p.section = StoragePropertySection::SelftestLog; - p.value = get_node_data(json_root_node, "ata_smart_self_test_log/extended/revision").value_or(0); + p.value = get_node_data(json_root_node, log_key + "/revision").value_or(0); add_property(p); section_properties_found = true; } @@ -905,9 +910,9 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft // Count { StorageProperty p; - p.set_name("ata_smart_self_test_log/extended/count", _("Self-test count")); + p.set_name(log_key + "/count", _("Self-test count")); p.section = StoragePropertySection::SelftestLog; - p.value = get_node_data(json_root_node, "ata_smart_self_test_log/extended/count").value_or(0); + p.value = get_node_data(json_root_node, log_key + "/count").value_or(0); p.show_in_ui = false; add_property(p); counts.emplace_back(fmt::format("Self-test entries: {}", p.get_value())); @@ -915,9 +920,9 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft // Error Count { StorageProperty p; - p.set_name("ata_smart_self_test_log/extended/error_count_total", _("Total error count")); + p.set_name(log_key + "/error_count_total", _("Total error count")); p.section = StoragePropertySection::SelftestLog; - p.value = get_node_data(json_root_node, "ata_smart_self_test_log/extended/error_count_total").value_or(0); + p.value = get_node_data(json_root_node, log_key + "/error_count_total").value_or(0); p.show_in_ui = false; add_property(p); counts.emplace_back(fmt::format("Total error count: {}", p.get_value())); @@ -925,9 +930,9 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft // Outdated Error Count { StorageProperty p; - p.set_name("ata_smart_self_test_log/extended/error_count_outdated", _("Outdated error count")); + p.set_name(log_key + "/error_count_outdated", _("Outdated error count")); p.section = StoragePropertySection::SelftestLog; - p.value = get_node_data(json_root_node, "ata_smart_self_test_log/extended/error_count_outdated").value_or(0); + p.value = get_node_data(json_root_node, log_key + "/error_count_outdated").value_or(0); p.show_in_ui = false; add_property(p); counts.emplace_back(fmt::format("Outdated error count: {}", p.get_value())); @@ -936,7 +941,7 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft // Displayed Counts if (!counts.empty()) { StorageProperty p; - p.set_name("ata_smart_self_test_log/extended/_counts", _("Entries")); + p.set_name(log_key + "/_counts", _("Entries")); p.section = StoragePropertySection::SelftestLog; p.value = hz::string_join(counts, "; "); add_property(p); @@ -944,7 +949,7 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft section_properties_found = true; } - const std::string table_key = "ata_smart_self_test_log/extended/table"; + const std::string table_key = log_key + "/table"; auto table_node = get_node(json_root_node, table_key); // Entries @@ -955,7 +960,7 @@ hz::ExpectedVoid SmartctlJsonAtaParser::parse_section_selft entry.test_num = entry_num; entry.type = get_node_data(table_entry, "type/string").value_or(std::string()); // FIXME use type/value for i18n entry.status_str = get_node_data(table_entry, "status/string").value_or(std::string()); - entry.remaining_percent = get_node_data(table_entry, "status/remaining_percent").value_or(0); + entry.remaining_percent = get_node_data(table_entry, "status/remaining_percent").value_or(-1); // extended only entry.lifetime_hours = get_node_data(table_entry, "lifetime_hours").value_or(0); entry.passed = get_node_data(table_entry, "status/passed").value_or(false); diff --git a/src/applib/storage_property_descr.cpp b/src/applib/storage_property_descr.cpp index 68f6878..2418bfa 100644 --- a/src/applib/storage_property_descr.cpp +++ b/src/applib/storage_property_descr.cpp @@ -140,7 +140,9 @@ bool storage_property_autoset_description(StorageProperty& p, StorageDeviceDetec case StoragePropertySection::SelftestLog: found = auto_set(p, "ata_smart_self_test_log/extended/revision", p.displayable_name.c_str()) - || auto_set(p, "ata_smart_self_test_log/extended/table/count", "Number of tests in selftest log. Note: The number of entries may be limited to the newest manual tests."); + || auto_set(p, "ata_smart_self_test_log/standard/revision", p.displayable_name.c_str()) + || auto_set(p, "ata_smart_self_test_log/extended/count", "Number of tests in selftest log. Note: The number of entries may be limited to the newest manual tests.") + || auto_set(p, "ata_smart_self_test_log/standard/count", "Number of tests in selftest log. Note: The number of entries may be limited to the newest manual tests."); // || auto_set(p, "ata_smart_self_test_log/_present", "This device does not support self-test logging."); // the property text already says that break; diff --git a/src/gui/gsc_info_window.cpp b/src/gui/gsc_info_window.cpp index b43d3b2..8d7ce02 100644 --- a/src/gui/gsc_info_window.cpp +++ b/src/gui/gsc_info_window.cpp @@ -1521,7 +1521,9 @@ void GscInfoWindow::fill_ui_self_test_log(const StoragePropertyRepository& prope row[columns_->self_test_log_table_columns.log_entry_index] = entry.test_num; row[columns_->self_test_log_table_columns.type] = Glib::Markup::escape_text(entry.type); row[columns_->self_test_log_table_columns.status] = Glib::Markup::escape_text(entry.get_readable_status()); - row[columns_->self_test_log_table_columns.percent] = Glib::Markup::escape_text(hz::number_to_string_locale(100 - entry.remaining_percent) + "%"); + if (entry.remaining_percent != -1) { // only extended log supports this + row[columns_->self_test_log_table_columns.percent] = Glib::Markup::escape_text(hz::number_to_string_locale(100 - entry.remaining_percent) + "%"); + } row[columns_->self_test_log_table_columns.hours] = Glib::Markup::escape_text(hz::number_to_string_locale(entry.lifetime_hours)); row[columns_->self_test_log_table_columns.lba] = Glib::Markup::escape_text(entry.lba_of_first_error);