Improved parser so that all the "-x" test data is parsed.

This commit is contained in:
Alexander Shaduri
2017-09-05 20:53:19 +00:00
parent 675fad3fc1
commit b9160ec173
2 changed files with 166 additions and 16 deletions
+165 -16
View File
@@ -161,6 +161,52 @@ bool SmartctlParser::parse_full(const std::string& full, StorageAttribute::DiskT
app_pcre_replace(re4, "\n" + match + "\n", s); // add extra newlines
}
// Some errors get in the way of subsection detection and have little value, remove them.
{
// "ATA_READ_LOG_EXT (addr=0x00:0x00, page=0, n=1) failed: 48-bit ATA commands not implemented"
// or "ATA_READ_LOG_EXT (addr=0x11:0x00, page=0, n=1) failed: scsi error aborted command"
// in front of "Read GP Log Directory failed" and "Read SATA Phy Event Counters failed".
pcrecpp::RE re1 = app_pcre_re("/^(ATA_READ_LOG_EXT \\([^)]+\\) failed: .*)$/mi");
// "SMART WRITE LOG does not return COUNT and LBA_LOW register"
// in front of "SCT (Get) Error Recovery Control command failed" (scterc section)
pcrecpp::RE re2= app_pcre_re("/^((?:Error )?SMART WRITE LOG does not return COUNT and LBA_LOW register)$/mi");
// "Read SCT Status failed: scsi error aborted command"
// in front of "Read SCT Temperature History failed" and "SCT (Get) Error Recovery Control command failed"
pcrecpp::RE re3= app_pcre_re("/^(Read SCT Status failed: .*)$/mi");
// "Unknown SCT Status format version 0, should be 2 or 3."
pcrecpp::RE re4= app_pcre_re("/^(Unknown SCT Status format version .*)$/mi");
// "Read SCT Data Table failed: scsi error aborted command"
pcrecpp::RE re5= app_pcre_re("/^(Read SCT Data Table failed: .*)$/mi");
// "Write SCT Data Table failed: Undefined error: 0"
// in front of "Read SCT Temperature History failed"
pcrecpp::RE re6= app_pcre_re("/^(Write SCT Data Table failed: .*)$/mi");
// "Unexpected SCT status 0x0000 (action_code=0, function_code=0)"
// in front of "Read SCT Temperature History failed"
pcrecpp::RE re7= app_pcre_re("/^(Unexpected SCT status .*\\))$/mi");
std::string match;
if (app_pcre_match(re1, s, &match))
app_pcre_replace(re1, "", s); // add extra newlines
if (app_pcre_match(re2, s, &match))
app_pcre_replace(re2, "", s); // add extra newlines
if (app_pcre_match(re3, s, &match))
app_pcre_replace(re3, "", s); // add extra newlines
if (app_pcre_match(re4, s, &match))
app_pcre_replace(re4, "", s); // add extra newlines
if (app_pcre_match(re5, s, &match))
app_pcre_replace(re5, "", s); // add extra newlines
if (app_pcre_match(re6, s, &match))
app_pcre_replace(re6, "", s); // add extra newlines
if (app_pcre_match(re7, s, &match))
app_pcre_replace(re7, "", s); // add extra newlines
}
// ------------------- Parsing
@@ -429,6 +475,29 @@ http://knowledge.seagate.com/articles/en_US/FAQ/213891en
if (app_pcre_match("/mandatory SMART command failed/mi", line)) {
continue;
}
// --get=all may cause these, ignore.
// "Unexpected SCT status 0x0010 (action_code=4, function_code=2)"
if (app_pcre_match("/^Unexpected SCT status/mi", line)
// "Write SCT (Get) XXX Error Recovery Control Command failed: scsi error aborted command"
|| app_pcre_match("/^Write SCT \\(Get\\) XXX Error Recovery Control Command failed/mi", line)
// "Write SCT (Get) Feature Control Command failed: scsi error aborted command"
|| app_pcre_match("/^Write SCT \\(Get\\) Feature Control Command failed/mi", line)
// "Read SCT Status failed: scsi error aborted command"
|| app_pcre_match("/^Read SCT Status failed/mi", line)
// "Read SMART Data failed: Input/output error" (just ignore this, the rest of the data seems fine)
|| app_pcre_match("/^Read SMART Data failed/mi", line)
// "Unknown SCT Status format version 0, should be 2 or 3."
|| app_pcre_match("/^Unknown SCT Status format version/mi", line)
// "Read SMART Thresholds failed: scsi error aborted command"
|| app_pcre_match("/^Read SMART Thresholds failed/mi", line)
// " Enabled status cached by OS, trying SMART RETURN STATUS cmd."
|| app_pcre_match("/Enabled status cached by OS, trying SMART RETURN STATUS cmd/mi", line)
|| app_pcre_match("/^>> Terminate command early due to bad response to IEC mode page/mi", line) // on a flash drive
// "scsiModePageOffset: response length too short, resp_len=4 offset=4 bd_len=0"
|| app_pcre_match("/^scsiModePageOffset: .+/mi", line) // on a flash drive
) {
continue;
}
if (re.FullMatch(line, &name, &value)) {
hz::string_trim(name);
@@ -506,6 +575,11 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
p.value_type = StorageProperty::value_type_string;
p.value_string = p.reported_value;
} else if (app_pcre_match("/^Add. Product Id$/mi", p.reported_name)) {
p.set_name(p.reported_name, "add_product_id", "Additional Product ID");
p.value_type = StorageProperty::value_type_string;
p.value_string = p.reported_value;
} else if (app_pcre_match("/^Firmware Version$/mi", p.reported_name)) {
p.set_name(p.reported_name, "firmware_version", "Firmware Version");
p.value_type = StorageProperty::value_type_string;
@@ -639,6 +713,11 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
p.value_type = StorageProperty::value_type_string;
p.value_string = p.reported_value;
} else if (app_pcre_match("/^DSN feature is$/mi", p.reported_name)) {
p.set_name(p.reported_name, "dsn_feature", "DSN Feature");
p.value_type = StorageProperty::value_type_string;
p.value_string = p.reported_value;
} else if (app_pcre_match("/^Power mode (?:was|is)$/mi", p.reported_name)) {
p.set_name(p.reported_name, "power_mode", "Power Mode");
p.value_type = StorageProperty::value_type_string;
@@ -728,7 +807,11 @@ bool SmartctlParser::parse_section_data(const std::string& body)
} else if (app_pcre_match("/^General Purpose Log Directory Version/mi", sub) // -l directory
|| app_pcre_match("/^General Purpose Log Directory not supported/mi", sub)
|| app_pcre_match("/^Read GP Log Directory failed/mi", sub) ) {
|| app_pcre_match("/^General Purpose Logging \\(GPL\\) feature set supported/mi", sub)
|| app_pcre_match("/^Read GP Log Directory failed/mi", sub)
|| app_pcre_match("/^Log Directories not read due to '-F nologdir' option/mi", sub)
|| app_pcre_match("/^Read SMART Log Directory failed/mi", sub)
|| app_pcre_match("/^SMART Log Directory Version/mi", sub) ) { // old smartctl
status = parse_section_data_subsection_directory_log(sub) || status;
} else if (app_pcre_match("/^SMART Error Log Version/mi", sub) // -l error
@@ -739,6 +822,7 @@ bool SmartctlParser::parse_section_data(const std::string& body)
status = parse_section_data_subsection_error_log(sub) || status;
} else if (app_pcre_match("/^SMART Extended Comprehensive Error Log \\(GP Log 0x03\\) not supported/mi", sub) // -l xerror
|| app_pcre_match("/^SMART Extended Comprehensive Error Log size (.*) not supported/mi", sub)
|| app_pcre_match("/^Read SMART Extended Comprehensive Error Log failed/mi", sub) ) { // -l xerror
// These are printed with "-l xerror,error" if falling back to "error". They're in their own sections, ignore them.
// We don't support showing these messages.
@@ -767,21 +851,30 @@ bool SmartctlParser::parse_section_data(const std::string& body)
} else if (app_pcre_match("/^SCT Status Version/mi", sub)
// "SCT Commands not supported"
// "SCT Commands not supported if ATA Security is LOCKED"
|| app_pcre_match("/SCT Commands not supported/mi", sub)
|| app_pcre_match("/SCT Data Table command not supported/mi", sub)
|| app_pcre_match("/Warning: device does not support SCT Commands/mi", sub) ) { // old smartctl
// "Error unknown SCT Temperature History Format Version (3), should be 2."
|| app_pcre_match("/^SCT Commands not supported/mi", sub)
|| app_pcre_match("/^SCT Data Table command not supported/mi", sub)
|| app_pcre_match("/^Error unknown SCT Temperature History Format Version/mi", sub)
|| app_pcre_match("/^Warning: device does not support SCT Commands/mi", sub) ) { // old smartctl
status = parse_section_data_subsection_scttemp_log(sub) || status;
} else if (app_pcre_match("/^SCT Error Recovery Control/mi", sub)
// Can be the same "SCT Commands not supported" as scttemp.
|| app_pcre_match("/^SCT Error Recovery Control command not supported/mi", sub)
|| app_pcre_match("/^SCT \\(Get\\) Error Recovery Control command failed/mi", sub) ) {
|| app_pcre_match("/^SCT \\(Get\\) Error Recovery Control command failed/mi", sub)
|| app_pcre_match("/^Warning: device does not support SCT \\(Get\\) Error Recovery Control/mi", sub) ) { // old smartctl
status = parse_section_data_subsection_scterc_log(sub) || status;
} else if (app_pcre_match("/^Device Statistics/mi", sub) // -l devstat
|| app_pcre_match("/^Device Statistics \\(GP\\/SMART Log 0x04\\) not supported/mi", sub) ) {
} else if (app_pcre_match("/^Device Statistics \\([^)]+\\)$/mi", sub) // -l devstat
|| app_pcre_match("/^Device Statistics \\([^)]+\\) not supported/mi", sub)
|| app_pcre_match("/^Read Device Statistics page (?:.+) failed/mi", sub) ) {
status = parse_section_data_subsection_devstat(sub) || status;
// "Device Statistics (GP Log 0x04) supported pages"
} else if (app_pcre_match("/^Device Statistics \\([^)]+\\) supported pages/mi", sub) ) { // not sure where it came from
// We don't support this section.
status = false;
} else if (app_pcre_match("/^SATA Phy Event Counters/mi", sub) // -l sataphy
|| app_pcre_match("/^SATA Phy Event Counters \\(GP Log 0x11\\) not supported/mi", sub)
|| app_pcre_match("/^SATA Phy Event Counters with [0-9-]+ sectors not supported/mi", sub)
@@ -2134,8 +2227,32 @@ Page Offset Size Value Flags Description
0x03 ===== = = === == Rotating Media Statistics (rev 1) ==
0x03 0x008 4 6356 -D- Spindle Motor Power-on Hours
0x03 0x010 4 6356 -D- Head Flying Hours
|||_ C monitored condition met
||__ D supports DSN
|___ N normalized value
*/
// Old (6.3) format:
/*
Page Offset Size Value Description
1 ===== = = == General Statistics (rev 2) ==
1 0x008 4 2 Lifetime Power-On Resets
1 0x018 6 1480289770 Logical Sectors Written
1 0x020 6 28939977 Number of Write Commands
1 0x028 6 3331436 Logical Sectors Read
1 0x030 6 122181 Number of Read Commands
1 0x038 6 12715200000 Date and Time TimeStamp
7 ===== = = == Solid State Device Statistics (rev 1) ==
7 0x008 1 1~ Percentage Used Endurance Indicator
|_ ~ normalized value
*/
enum {
FormatStyleNoFlags, // 6.3 and older
FormatStyleCurrent, // 6.5
};
// supported / unsupported
bool supported = true;
{
@@ -2164,35 +2281,67 @@ Page Offset Size Value Flags Description
std::string flag_re = "([A-Z=-]{3,})";
// Page Offset Size Value Flags Description
std::string line_re = "[ \\t]*([0-9a-z]+)" + space_re + "([0-9a-z=]+)" + space_re + "([0-9=]+)" + space_re + "([0-9=-]+)" + space_re + flag_re + space_re + "(.+)";
pcrecpp::RE re_stat_line = app_pcre_re("/" + line_re + "/mi");
pcrecpp::RE line_re = app_pcre_re("/[ \\t]*([0-9a-z]+)" + space_re + "([0-9a-z=]+)" + space_re + "([0-9=]+)"
+ space_re + "([0-9=-]+)" + space_re + flag_re + space_re + "(.+)/mi");
// Page Offset Size Value Description
pcrecpp::RE line_re_noflags = app_pcre_re("/[ \\t]*([0-9a-z]+)" + space_re + "([0-9a-z=]+)" + space_re + "([0-9=]+)"
+ space_re + "([0-9=~-]+)" + space_re + "(.+)/mi");
// flag description lines
pcrecpp::RE re_flag_descr = app_pcre_re("/^[\\t ]+\\|/mi");
int devstat_format_style = FormatStyleCurrent;
for(unsigned int i = 0; i < lines.size(); ++i) {
const std::string& line = lines[i];
// skip the non-informative lines
// "Device Statistics (GP Log 0x04)"
// "Device Statistics (SMART Log 0x04)"
// "ATA_SMART_READ_LOG failed: Undefined error: 0"
// "Read Device Statistics page 0x00 failed"
// "Read Device Statistics pages 0x00-0x07 failed"
if (line.empty()
|| app_pcre_match("/Device Statistics \\(GP Log 0x04\\)/mi", line)
|| app_pcre_match("/Page[ \\t]+Offset[ \\t]+Size/mi", line)) {
|| app_pcre_match("/^Device Statistics \\((?:GP|SMART) Log 0x04\\)/mi", line)
|| app_pcre_match("/^ATA_SMART_READ_LOG failed:/mi", line)
|| app_pcre_match("/^Read Device Statistics page (?:.+) failed/mi", line)
|| app_pcre_match("/^Read Device Statistics pages (?:.+) failed/mi", line) ) {
continue;
}
// Table header
if (app_pcre_match("/^Page[\\t ]+Offset[\\t ]+Size/mi", line)) {
// detect format type
if (!app_pcre_match("/[\\t ]+Flags[\\t ]+/mi", line)) {
devstat_format_style = FormatStyleNoFlags;
}
continue; // we don't need this line
}
if (re_flag_descr.PartialMatch(line)) { // " |||_ C monitored condition met", etc...
continue; // skip flag description lines
}
std::string page, offset, size, value, flags, description;
bool matched = true;
if (!re_stat_line.FullMatch(line, &page, &offset, &size, &value, &flags, &description)) {
matched = false;
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse devstat line.\n");
bool matched = false;
if (devstat_format_style == FormatStyleCurrent) {
if (line_re.FullMatch(line, &page, &offset, &size, &value, &flags, &description)) {
matched = true;
}
} else if (devstat_format_style == FormatStyleNoFlags) {
if (line_re_noflags.FullMatch(line, &page, &offset, &size, &value, &description)) {
matched = true;
flags = "---"; // to keep consistent with the Current format
if (!value.empty() && value.back() == '~') { // normalized
flags = "N--";
value.resize(value.size() - 1);
}
}
}
if (!matched) {
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse devstat line.\n");
debug_out_dump("app", "------------ Begin unparsable devstat line dump ------------\n");
debug_out_dump("app", line << "\n");
debug_out_dump("app", "------------- End unparsable devstat line dump -------------\n");
@@ -1567,6 +1567,7 @@ bool storage_property_autoset_description(StorageProperty& p, StorageAttribute::
|| auto_set(p, "aam_feature", "Automatic Acoustic Management (AAM) level")
|| auto_set(p, "apm_feature", "Automatic Power Management (APM) feature")
|| auto_set(p, "apm_level", "Advanced Power Management (APM) level")
|| auto_set(p, "dsn_feature", "Device Statistics Notification (DSN) feature")
|| auto_set(p, "power_mode", "Power mode at the time of query");
// set just its name as a tooltip