diff --git a/gsmartcontrol/TODO b/gsmartcontrol/TODO index d112f6a..e1cff35 100644 --- a/gsmartcontrol/TODO +++ b/gsmartcontrol/TODO @@ -23,6 +23,7 @@ TODO: Don't rely on smartctl return code (2), parse the output instead. This will allow us to show the Info page. + Need usage cases. Areca detection @@ -69,10 +70,6 @@ Testing: Pre-failure: P, old age: -. Maybe get rid of Type and Updated columns and print only decoded flags? - use -l xerror,error -l xselftest,selftest by default (the output is similar). - Maybe increase default number of entries (50?). - Change this text: "Note: Usually only the last five errors are stored." - Add a tab for -l devstat - it shows interesting statistics. Some of this stuff is better than attributes, maybe show them before attributes. Also needs the warnings and descriptions. diff --git a/gsmartcontrol/src/applib/smartctl_parser.cpp b/gsmartcontrol/src/applib/smartctl_parser.cpp index 7ca146f..7e377b1 100644 --- a/gsmartcontrol/src/applib/smartctl_parser.cpp +++ b/gsmartcontrol/src/applib/smartctl_parser.cpp @@ -645,12 +645,14 @@ bool SmartctlParser::parse_section_data(const std::string& body) } else if (app_pcre_match("/SMART Attributes Data Structure/mi", sub)) { status = parse_section_data_subsection_attributes(sub) || status; - } else if (app_pcre_match("/SMART Error Log Version/mi", sub) + } else if (app_pcre_match("/SMART Error Log Version/mi", sub) // -l error + || app_pcre_match("/SMART Extended Comprehensive Error Log Version/mi", sub) // -l xerror || app_pcre_match("/Warning: device does not support Error Logging/mi", sub) || app_pcre_match("/SMART Error Log not supported/mi", sub)) { status = parse_section_data_subsection_error_log(sub) || status; - } else if (app_pcre_match("/SMART Self-test log/mi", sub) + } else if (app_pcre_match("/SMART Self-test log/mi", sub) // -l selftest + || app_pcre_match("/SMART Extended Self-test Log Version/mi", sub) // -l error xselftest || app_pcre_match("/Warning: device does not support Self Test Logging/mi", sub) || app_pcre_match("/SMART Self-test Log not supported/mi", sub)) { status = parse_section_data_subsection_selftest_log(sub) || status; @@ -1350,7 +1352,9 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string& // Error log version { - pcrecpp::RE re = app_pcre_re("/^(SMART Error Log Version):[ \\t]*(.*)$/mi"); + // SMART Error Log Version: 1 + // SMART Extended Comprehensive Error Log Version: 1 (1 sectors) + pcrecpp::RE re = app_pcre_re("/^(SMART (Extended Comprehensive )?Error Log Version): ([0-9]+).*?$/mi"); std::string name, value; if (re.PartialMatch(sub, &name, &value)) { @@ -1384,7 +1388,7 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string& } } - // Error log enty count + // Error log entry count { // note: these represent the same information pcrecpp::RE re1 = app_pcre_re("/^ATA Error Count:[ \\t]*([0-9]+)/mi"); @@ -1413,14 +1417,17 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string& // individual errors { // split by blocks - pcrecpp::RE re_block = app_pcre_re("/^((Error[ \\t]*([0-9]+))[ \\t]*occurred at disk power-on lifetime:[ \\t]*([0-9]+) hours.*(?:\\n(?: |\\n ).*)*)/mi"); + // "Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)" + // "Error 25 occurred at disk power-on lifetime: 14799 hours" + pcrecpp::RE re_block = app_pcre_re("/^((Error[ \\t]*([0-9]+))[ \\t]*(?:\\[[0-9]+\\][ \\t])?occurred at disk power-on lifetime:[ \\t]*([0-9]+) hours(?:[^\\n]*)?.*(?:\\n(?: |\\n ).*)*)/mi"); // " When the command that caused the error occurred, the device was active or idle." // Note: For "in an unknown state" - remove first two words. pcrecpp::RE re_state = app_pcre_re("/occurred, the device was[ \\t]*(?: in)?(?: an?)?[ \\t]+([^.\\n]*)\\.?/mi"); // " 84 51 2c 71 cd 3f e6 Error: ICRC, ABRT 44 sectors at LBA = 0x063fcd71 = 104844657" // " 40 51 00 f5 41 61 e0 Error: UNC at LBA = 0x006141f5 = 6373877" - pcrecpp::RE re_type = app_pcre_re("/[ \\t]+Error:[ \\t]*([ ,a-z]+)[ \\t]+((?:[0-9]+|at )[ \\t]*.*)$/mi"); + // " 02 -- 51 00 00 00 00 00 00 00 00 00 00 Error: TK0NF" + pcrecpp::RE re_type = app_pcre_re("/[ \\t]+Error:[ \\t]*([ ,a-z0-9]+)(?:[ \\t]+((?:[0-9]+|at )[ \\t]*.*))?$/mi"); std::string block, name, value_num, value_time; pcrecpp::StringPiece input(sub); // position tracker @@ -1504,7 +1511,7 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin // The whole subsection { StorageProperty p(pt); - p.set_name("SMART Self-test log", "selftest_log"); + p.set_name("SMART Self-Test Log", "selftest_log"); p.reported_value = sub; p.value_type = StorageProperty::value_type_string; p.value_string = p.reported_value; @@ -1529,13 +1536,15 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin // Self-test log version { - // newer smartctl (since smartctl 5.1-16) + // SMART Self-test log structure revision number 1 + // SMART Extended Self-test Log Version: 1 (1 sectors) pcrecpp::RE re1 = app_pcre_re("/(SMART Self-test log structure[^\\n0-9]*)([^ \\n]+)[ \\t]*$/mi"); - // older smartctl + pcrecpp::RE re1_ex = app_pcre_re("/(SMART Extended Self-test Log Version: ([0-9]+).*$/mi"); + // older smartctl (pre 5.1-16) pcrecpp::RE re2 = app_pcre_re("/(SMART Self-test log, version number[^\\n0-9]*)([^ \\n]+)[ \\t]*$/mi"); std::string name, value; - if (re1.PartialMatch(sub, &name, &value) || re2.PartialMatch(sub, &name, &value)) { + if (re1.PartialMatch(sub, &name, &value) || re1_ex.PartialMatch(sub, &name, &value) || re2.PartialMatch(sub, &name, &value)) { hz::string_trim(value); StorageProperty p(pt); diff --git a/gsmartcontrol/src/applib/storage_device.cpp b/gsmartcontrol/src/applib/storage_device.cpp index 6060154..80833e5 100644 --- a/gsmartcontrol/src/applib/storage_device.cpp +++ b/gsmartcontrol/src/applib/storage_device.cpp @@ -324,10 +324,10 @@ std::string StorageDevice::fetch_data_and_parse(hz::intrusive_ptr sma if (this->get_type_argument() == "scsi") { // not sure about correctness... FIXME probably fails with RAID/scsi // This doesn't do much yet, but just in case... // SCSI equivalent of -a --get=all: - error_msg = execute_device_smartctl("--health --info --get=all --attributes --log=error --log=selftest", smartctl_ex, output); + error_msg = execute_device_smartctl("--health --info --get=all --attributes --log=xerror,50,error --log=xselftest,50,selftest", smartctl_ex, output); } else { // ATA equivalent of -a --get=all: - error_msg = execute_device_smartctl("--health --info --get=all --capabilities --attributes --log=error --log=selftest --log=selective", + error_msg = execute_device_smartctl("--health --info --get=all --capabilities --attributes --log=xerror,50,error --log=xselftest,50,selftest --log=selective", smartctl_ex, output, true); // set type to invalid if needed } // See notes above (in fetch_basic_data_and_parse()). diff --git a/gsmartcontrol/src/applib/storage_property.h b/gsmartcontrol/src/applib/storage_property.h index 314c661..6ac056e 100644 --- a/gsmartcontrol/src/applib/storage_property.h +++ b/gsmartcontrol/src/applib/storage_property.h @@ -339,8 +339,8 @@ class StorageProperty { subsection_health, ///< Overall-health (-H, --health) subsection_capabilities, ///< General SMART Values, aka Capabilities (-c, --capabilities) subsection_attributes, ///< Attributes (-A, --attributes). These need decoding. - subsection_error_log, ///< Error Log (-l error) - subsection_selftest_log, ///< Self-test log (-l selftest) + subsection_error_log, ///< Error Log (--log=error) + subsection_selftest_log, ///< Self-test log (--log=selftest) subsection_selective_selftest_log ///< Selective self-test log and settings }; diff --git a/gsmartcontrol/src/gsc_info_window.cpp b/gsmartcontrol/src/gsc_info_window.cpp index 58e5e73..1c535f7 100644 --- a/gsmartcontrol/src/gsc_info_window.cpp +++ b/gsmartcontrol/src/gsc_info_window.cpp @@ -849,7 +849,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests } else if (iter->value_type != StorageProperty::value_type_error_block) { label_strings.push_back(PropertyLabel(iter->readable_name + ": " + iter->format_value(), &(*iter))); if (iter->generic_name == "error_count") - label_strings.back().label += " (Note: Usually only the last five errors are stored.)"; + label_strings.back().label += " (Note: The number of entries may be limited to the newest ones)"; } else { std::string type_details = iter->value_error_block.type_more_info; diff --git a/gsmartcontrol/src/res/gsc_info_window.ui b/gsmartcontrol/src/res/gsc_info_window.ui index 7cd2df0..606071b 100644 --- a/gsmartcontrol/src/res/gsc_info_window.ui +++ b/gsmartcontrol/src/res/gsc_info_window.ui @@ -197,6 +197,7 @@ True False + vertical 3 @@ -380,6 +381,7 @@ True False + vertical 3 @@ -938,8 +940,8 @@ Selective self-test log is also presented here. True Re-read all the information True - + True