From a94f74ee74bb74643716502e2dac6eeebfcdba8e Mon Sep 17 00:00:00 2001 From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137> Date: Thu, 29 Oct 2009 22:52:38 +0000 Subject: [PATCH] Add '-v ID,RAW_FORMAT[,ATTR_NAME]' option. Rework attribute name and raw value formatting. git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@2975 4ea69e1a-61f1-4043-bf83-b5c94c648137 --- smartmontools/CHANGELOG | 4 + smartmontools/atacmds.cpp | 796 ++++++++++++++-------------------- smartmontools/atacmds.h | 84 +++- smartmontools/ataprint.cpp | 46 +- smartmontools/ataprint.h | 12 +- smartmontools/knowndrives.cpp | 37 +- smartmontools/knowndrives.h | 4 +- smartmontools/smartctl.cpp | 2 +- smartmontools/smartd.cpp | 53 +-- 9 files changed, 448 insertions(+), 590 deletions(-) diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG index bad312df7..07cb6e653 100644 --- a/smartmontools/CHANGELOG +++ b/smartmontools/CHANGELOG @@ -43,6 +43,10 @@ NOTES FOR FUTURE RELEASES: see TODO file. <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE> + [CF] Add '-v ID,RAW_FORMAT[,ATTR_NAME]' option. This allows to add new + attributes without the need to enhance the '-v' option. + Rework attribute name and raw value formatting. + [CF] Fix auto_ptr initialization in linux_scsi_device::autodetect_open(). [CF] Remove duplicate function smart_device_list::add(). diff --git a/smartmontools/atacmds.cpp b/smartmontools/atacmds.cpp index 09d843a6b..37698d640 100644 --- a/smartmontools/atacmds.cpp +++ b/smartmontools/atacmds.cpp @@ -146,58 +146,17 @@ static const int actual_ver[] = { 6 /* 0x0022 WARNING: */ }; -// When you add additional items to this list, you should then: -// 0 -- update this list -// 1 -- if needed, modify ataPrintSmartAttribRawValue() -// 2 - if needed, modify ataPrintSmartAttribName() -// 3 -- add drive in question into builtin_knowndrives[] table in knowndrives.cpp -// 4 -- update smartctl.8 -// 5 -- update smartd.8 -// 6 -- do "make smartd.conf.5" to update smartd.conf.5 -// 7 -- update CHANGELOG file - -struct vendor_attr_arg_entry -{ - unsigned char id; // attribute ID, 0 for all - const char * name; // attribute name - unsigned char val; // value for attribute defs array -}; - -// The order of these entries is (only) relevant for '-v help' output. -const vendor_attr_arg_entry vendor_attribute_args[] = { - { 9,"halfminutes", 4}, - { 9,"minutes", 1}, - { 9,"seconds", 3}, - { 9,"temp", 2}, - {192,"emergencyretractcyclect", 1}, - {193,"loadunload", 1}, - {194,"10xCelsius", 1}, - {194,"unknown", 2}, - {197,"increasing", 1}, - {198,"offlinescanuncsectorct", 2}, - {198,"increasing", 1}, - {200,"writeerrorcount", 1}, - {201,"detectedtacount", 1}, - {220,"temp", 1}, - {225,"hostwritescount", 1}, - {240,"transfererrorrate", 1}, - { 0,"raw8", 253}, - { 0,"raw16", 254}, - { 0,"raw48", 255}, -}; - -const unsigned num_vendor_attribute_args = sizeof(vendor_attribute_args)/sizeof(vendor_attribute_args[0]); - // Get ID and increase flag of current pending or offline // uncorrectable attribute. -unsigned char get_unc_attr_id(bool offline, const unsigned char * defs, +unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs, bool & increase) { unsigned char id = (!offline ? 197 : 198); - increase = (defs[id] == 1); + increase = !!(defs[id].flags & ATTRFLAG_INCREASING); return id; } +#if 0 // TODO: never used // This are the meanings of the Self-test failure checkpoint byte. // This is in the self-test log at offset 4 bytes into the self-test // descriptor and in the SMART READ DATA structure at byte offset @@ -223,63 +182,134 @@ const char *SelfTestFailureCodeName(unsigned char which){ return NULL; } } +#endif + -// This is a utility function for parsing pairs like "9,minutes" or -// "220,temp", and putting the correct flag into the attributedefs -// array. Returns 1 if problem, 0 if pair has been recongized. -int parse_attribute_def(const char * pair, unsigned char * defs) +// Table of raw print format names +struct format_name_entry { - int id = 0, nc = -1; - char name[32+1]; - if (pair[0] == 'N') { - // "N,name" - if (!(sscanf(pair, "N,%32s%n", name, &nc) == 1 && nc == (int)strlen(pair))) - return 1; + const char * name; + ata_attr_raw_format format; +}; + +const format_name_entry format_names[] = { + {"raw8" , RAWFMT_RAW8}, + {"raw16" , RAWFMT_RAW16}, + {"raw48" , RAWFMT_RAW48}, + {"raw16(raw16)" , RAWFMT_RAW16_OPT_RAW16}, + {"raw16(avg16)" , RAWFMT_RAW16_OPT_AVG16}, + {"raw24/raw24" , RAWFMT_RAW24_RAW24}, + {"sec2hour" , RAWFMT_SEC2HOUR}, + {"min2hour" , RAWFMT_MIN2HOUR}, + {"halfmin2hour" , RAWFMT_HALFMIN2HOUR}, + {"tempminmax" , RAWFMT_TEMPMINMAX}, + {"temp10x" , RAWFMT_TEMP10X}, +}; + +const unsigned num_format_names = sizeof(format_names)/sizeof(format_names[0]); + +// Table to map old to new '-v' option arguments +const char * map_old_vendor_opts[][2] = { + { "9,halfminutes" , "9,halfmin2hour,Power_On_Half_Minutes"}, + { "9,minutes" , "9,min2hour,Power_On_Minutes"}, + { "9,seconds" , "9,sec2hour,Power_On_Seconds"}, + { "9,temp" , "9,tempminmax,Temperature_Celsius"}, + {"192,emergencyretractcyclect" , "192,raw48,Emerg_Retract_Cycle_Ct"}, + {"193,loadunload" , "193,raw24/raw24"}, + {"194,10xCelsius" , "194,temp10x,Temperature_Celsius_x10"}, + {"194,unknown" , "194,raw48,Unknown_Attribute"}, + {"197,increasing" , "197,raw48+,Total_Pending_Sectors"}, // '+' sets flag + {"198,offlinescanuncsectorct" , "198,raw48,Offline_Scan_UNC_SectCt"}, + {"198,increasing" , "198,raw48+,Total_Offl_Uncorrectabl"}, // '+' sets flag + {"200,writeerrorcount" , "200,raw48,Write_Error_Count"}, + {"201,detectedtacount" , "201,raw48,Detected_TA_Count"}, + {"220,temp" , "220,raw48,Temperature_Celsius"}, +}; + +const unsigned num_old_vendor_opts = sizeof(map_old_vendor_opts)/sizeof(map_old_vendor_opts[0]); + +// Parse vendor attribute display def (-v option). +// Return false on error. +bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs, + ata_vendor_def_prior priority) +{ + // Map old -> new options + unsigned i; + for (i = 0; i < num_old_vendor_opts; i++) { + if (!strcmp(opt, map_old_vendor_opts[i][0])) { + opt = map_old_vendor_opts[i][1]; + break; + } + } + + // Parse option + int len = strlen(opt); + int id = 0, n1 = -1, n2 = -1; + char fmtname[32+1], attrname[32+1]; + if (opt[0] == 'N') { + // "N,format" + if (!(sscanf(opt, "N,%32[^,]%n", fmtname, &n1) == 1 && n1 == len)) + return false; } else { - // "attr,name" - if (!( sscanf(pair, "%d,%32s%n", &id, name, &nc) == 2 - && 1 <= id && id <= 255 && nc == (int)strlen(pair))) - return 1; + // "id,format[+][,name]" + if (!( sscanf(opt, "%d,%32[^,]%n,%32[^,]%n", &id, fmtname, &n1, attrname, &n2) >= 2 + && 1 <= id && id <= 255 && (n1 == len || n2 == len))) + return false; + if (n1 == len) + attrname[0] = 0; } - // Find pair - unsigned i; + unsigned flags = 0; + // For "-v 19[78],increasing" above + if (fmtname[strlen(fmtname)-1] == '+') { + fmtname[strlen(fmtname)-1] = 0; + flags = ATTRFLAG_INCREASING; + } + + // Find format name for (i = 0; ; i++) { - if (i >= num_vendor_attribute_args) - return 1; // Not found - if ( (!vendor_attribute_args[i].id || vendor_attribute_args[i].id == id) - && !strcmp(vendor_attribute_args[i].name, name) ) + if (i >= num_format_names) + return false; // Not found + if (!strcmp(fmtname, format_names[i].name)) break; } + ata_attr_raw_format format = format_names[i].format; if (!id) { - // "N,name" -> set all entries - for (int j = 0; j < MAX_ATTRIBUTE_NUM; j++) - defs[j] = vendor_attribute_args[i].val; + // "N,format" -> set format for all entries + for (int j = 0; j < MAX_ATTRIBUTE_NUM; j++) { + if (defs[j].priority >= priority) + continue; + defs[j].priority = priority; + defs[j].raw_format = format; + } + } + else if (defs[id].priority <= priority) { + // "id,format[,name]" + if (attrname[0]) + defs[id].name = attrname; + defs[id].raw_format = format; + defs[id].priority = priority; + defs[id].flags = flags; } - else - // "attr,name" - defs[id] = vendor_attribute_args[i].val; - return 0; + return true; } + // Return a multiline string containing a list of valid arguments for // parse_attribute_def(). The strings are preceeded by tabs and followed // (except for the last) by newlines. std::string create_vendor_attribute_arg_list() { std::string s; - for (unsigned i = 0; i < num_vendor_attribute_args; i++) { - if (i > 0) - s += '\n'; - if (!vendor_attribute_args[i].id) - s += "\tN,"; - else - s += strprintf("\t%d,", vendor_attribute_args[i].id); - s += vendor_attribute_args[i].name; - } + unsigned i; + for (i = 0; i < num_format_names; i++) + s += strprintf("%s\tN,%s[,ATTR_NAME]", + (i>0 ? "\n" : ""), format_names[i].name); + for (i = 0; i < num_old_vendor_opts; i++) + s += strprintf("\n\t%s", map_old_vendor_opts[i][0]); return s; } @@ -1741,293 +1771,209 @@ int ataCheckAttribute(const ata_smart_values * data, } -// Print temperature value and Min/Max value if present -static void ataPrintTemperatureValue(char *out, const unsigned char *raw, const unsigned *word) +// Get default raw value print format +static ata_attr_raw_format get_default_raw_format(unsigned char id) { - out+=sprintf(out, "%u", word[0]); - if (!word[1] && !word[2]) - return; // No Min/Max + switch (id) { + case 3: // Spin-up time + return RAWFMT_RAW16_OPT_AVG16; - unsigned lo = ~0, hi = ~0; - if (!raw[3]) { - // 00 HH 00 LL 00 TT (IBM) - hi = word[2]; lo = word[1]; - } - else if (!word[2]) { - // 00 00 HH LL 00 TT (Maxtor) - hi = raw[3]; lo = raw[2]; - } - if (lo > hi) { - unsigned t = lo; lo = hi; hi = t; + case 5: // Reallocated sector count + case 196: // Reallocated event count + return RAWFMT_RAW16_OPT_RAW16; + + case 190: // Temperature + case 194: + return RAWFMT_TEMPMINMAX; + + default: + return RAWFMT_RAW48; } - if (lo <= word[0] && word[0] <= hi) - sprintf(out, " (Lifetime Min/Max %u/%u)", lo, hi); - else - sprintf(out, " (%u %u %u %u)", raw[5], raw[4], raw[3], raw[2]); } +// Format attribute raw value. +std::string ata_format_attr_raw_value(const ata_smart_attribute & attribute, + const ata_vendor_attr_defs & defs) +{ + // Get print format + ata_attr_raw_format format = defs[attribute.id].raw_format; + if (format == RAWFMT_DEFAULT) + format = get_default_raw_format(attribute.id); -// This routine prints the raw value of an attribute as a text string -// into out. It also returns this 48-bit number as a long long. The -// array defs[] contains non-zero values if particular attributes have -// non-default interpretations. - -int64_t ataPrintSmartAttribRawValue(char *out, - const ata_smart_attribute * attribute, - const unsigned char * defs){ + // Get 48 bit raw value + const unsigned char * raw = attribute.raw; int64_t rawvalue; + rawvalue = raw[0] + | ( raw[1] << 8) + | ( raw[2] << 16) + | ((uint64_t)raw[3] << 24) + | ((uint64_t)raw[4] << 32) + | ((uint64_t)raw[5] << 40); + + // Get 16 bit words unsigned word[3]; - int j; - unsigned char select; - - // convert the six individual bytes to a long long (8 byte) integer. - // This is the value that we'll eventually return. - rawvalue = 0; - for (j=0; j<6; j++) { - // This looks a bit roundabout, but is necessary. Don't - // succumb to the temptation to use raw[j]<<(8*j) since under - // the normal rules this will be promoted to the native type. - // On a 32 bit machine this might then overflow. - int64_t temp; - temp = attribute->raw[j]; - temp <<= 8*j; - rawvalue |= temp; - } - - // convert quantities to three two-byte words - for (j=0; j<3; j++){ - word[j] = attribute->raw[2*j+1]; - word[j] <<= 8; - word[j] |= attribute->raw[2*j]; - } - - // if no data array, Attributes have default interpretations - if (defs) - select=defs[attribute->id]; - else - select=0; - - // Print six one-byte quantities. - if (select==253){ - for (j=0; j<5; j++) - out+=sprintf(out, "%d ", attribute->raw[5-j]); - out+=sprintf(out, "%d ", attribute->raw[0]); - return rawvalue; - } - - // Print three two-byte quantities - if (select==254){ - out+=sprintf(out, "%d %d %d", word[2], word[1], word[0]); - return rawvalue; - } - - // Print one six-byte quantity - if (select==255){ - out+=sprintf(out, "%"PRIu64, rawvalue); - return rawvalue; - } + word[0] = raw[0] | (raw[1] << 8); + word[1] = raw[2] | (raw[3] << 8); + word[2] = raw[4] | (raw[5] << 8); - // This switch statement is where we handle Raw attributes - // that are stored in an unusual vendor-specific format, - switch (attribute->id){ - // Spin-up time - case 3: - out+=sprintf(out, "%d", word[0]); - // if second nonzero then it stores the average spin-up time - if (word[1]) - out+=sprintf(out, " (Average %d)", word[1]); + // Print + std::string s; + switch (format) { + case RAWFMT_RAW8: + s = strprintf("%d %d %d %d %d %d", + raw[5], raw[4], raw[3], raw[2], raw[1], raw[0]); break; - // reallocated sector count - case 5: - out+=sprintf(out, "%u", word[0]); + + case RAWFMT_RAW16: + s = strprintf("%u %u %u", word[2], word[1], word[0]); + break; + + case RAWFMT_RAW48: + s = strprintf("%"PRIu64, rawvalue); + break; + + case RAWFMT_RAW16_OPT_RAW16: + s = strprintf("%u", word[0]); if (word[1] || word[2]) - out+=sprintf(out, " (%u, %u)", word[2], word[1]); + s += strprintf(" (%u, %u)", word[2], word[1]); break; - // Power on time - case 9: - if (select==1){ + + case RAWFMT_RAW16_OPT_AVG16: + s = strprintf("%u", word[0]); + if (word[1]) + s += strprintf(" (Average %u)", word[1]); + break; + + case RAWFMT_RAW24_RAW24: + s = strprintf("%d/%d", + raw[0] | (raw[1]<<8) | (raw[2]<<16), + raw[3] | (raw[4]<<8) | (raw[5]<<16)); + break; + + case RAWFMT_MIN2HOUR: + { // minutes - int64_t temp=word[0]+(word[1]<<16); - int64_t tmp1=temp/60; - int64_t tmp2=temp%60; - out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2); + int64_t temp = word[0]+(word[1]<<16); + int64_t tmp1 = temp/60; + int64_t tmp2 = temp%60; + s = strprintf("%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2); if (word[2]) - out+=sprintf(out, " (%u)", word[2]); + s += strprintf(" (%u)", word[2]); } - else if (select==3){ + break; + + case RAWFMT_SEC2HOUR: + { // seconds - int64_t hours=rawvalue/3600; - int64_t minutes=(rawvalue-3600*hours)/60; - int64_t seconds=rawvalue%60; - out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds); + int64_t hours = rawvalue/3600; + int64_t minutes = (rawvalue-3600*hours)/60; + int64_t seconds = rawvalue%60; + s = strprintf("%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds); } - else if (select==4){ - // 30-second counter - int64_t tmp1=rawvalue/120; - int64_t tmp2=(rawvalue-120*tmp1)/2; - out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2); - } - else - // hours - out+=sprintf(out, "%"PRIu64, rawvalue); //stored in hours break; - // Temperature - case 190: - ataPrintTemperatureValue(out, attribute->raw, word); - break; - // Load unload cycles - case 193: - if (select==1){ - // loadunload - long load =attribute->raw[0] + (attribute->raw[1]<<8) + (attribute->raw[2]<<16); - long unload=attribute->raw[3] + (attribute->raw[4]<<8) + (attribute->raw[5]<<16); - out+=sprintf(out, "%lu/%lu", load, unload); + + case RAWFMT_HALFMIN2HOUR: + { + // 30-second counter + int64_t hours = rawvalue/120; + int64_t minutes = (rawvalue-120*hours)/2; + s += strprintf("%"PRIu64"h+%02"PRIu64"m", hours, minutes); } - else - // associated - out+=sprintf(out, "%"PRIu64, rawvalue); break; + + case RAWFMT_TEMPMINMAX: // Temperature - case 194: - if (select==1){ - // ten times temperature in Celsius - int deg=word[0]/10; - int tenths=word[0]%10; - out+=sprintf(out, "%d.%d", deg, tenths); + s = strprintf("%u", word[0]); + if (word[1] || word[2]) { + unsigned lo = ~0, hi = ~0; + if (!raw[3]) { + // 00 HH 00 LL 00 TT (IBM) + hi = word[2]; lo = word[1]; + } + else if (!word[2]) { + // 00 00 HH LL 00 TT (Maxtor) + hi = raw[3]; lo = raw[2]; + } + if (lo > hi) { + unsigned t = lo; lo = hi; hi = t; + } + if (lo <= word[0] && word[0] <= hi) + s += strprintf(" (Lifetime Min/Max %u/%u)", lo, hi); + else + s += strprintf(" (%d %d %d %d)", raw[5], raw[4], raw[3], raw[2]); } - else if (select==2) - // unknown attribute - out+=sprintf(out, "%"PRIu64, rawvalue); - else - ataPrintTemperatureValue(out, attribute->raw, word); break; - // reallocated event count - case 196: - out+=sprintf(out, "%u", word[0]); - if (word[1] || word[2]) - out+=sprintf(out, " (%u, %u)", word[2], word[1]); + + case RAWFMT_TEMP10X: + // ten times temperature in Celsius + s = strprintf("%d.%d", word[0]/10, word[0]%10); break; + default: - out+=sprintf(out, "%"PRIu64, rawvalue); + s = "?"; // Should not happen + break; } - - // Return the full value - return rawvalue; -} + return s; +} -// Note some attribute names appear redundant because different -// manufacturers use different attribute IDs for an attribute with the -// same name. The variable val should contain a non-zero value if a particular -// attributes has a non-default interpretation. // Attribute names shouldn't be longer than 23 chars, otherwise they break the // output of smartctl. -void ataPrintSmartAttribName(char * out, unsigned char id, const unsigned char * definitions){ - const char *name; - unsigned char val; - - // If no data array, use default interpretations - if (definitions) - val=definitions[id]; - else - val=0; - - switch (id){ - +static const char * get_default_attr_name(unsigned char id) +{ + switch (id) { case 1: - name="Raw_Read_Error_Rate"; - break; + return "Raw_Read_Error_Rate"; case 2: - name="Throughput_Performance"; - break; + return "Throughput_Performance"; case 3: - name="Spin_Up_Time"; - break; + return "Spin_Up_Time"; case 4: - name="Start_Stop_Count"; - break; + return "Start_Stop_Count"; case 5: - name="Reallocated_Sector_Ct"; - break; + return "Reallocated_Sector_Ct"; case 6: - name="Read_Channel_Margin"; - break; + return "Read_Channel_Margin"; case 7: - name="Seek_Error_Rate"; - break; + return "Seek_Error_Rate"; case 8: - name="Seek_Time_Performance"; - break; + return "Seek_Time_Performance"; case 9: - switch (val) { - case 1: - name="Power_On_Minutes"; - break; - case 2: - name="Temperature_Celsius"; - break; - case 3: - name="Power_On_Seconds"; - break; - case 4: - name="Power_On_Half_Minutes"; - break; - default: - name="Power_On_Hours"; - break; - } - break; + return "Power_On_Hours"; case 10: - name="Spin_Retry_Count"; - break; + return "Spin_Retry_Count"; case 11: - name="Calibration_Retry_Count"; - break; + return "Calibration_Retry_Count"; case 12: - name="Power_Cycle_Count"; - break; + return "Power_Cycle_Count"; case 13: - name="Read_Soft_Error_Rate"; - break; + return "Read_Soft_Error_Rate"; case 175: - name="Program_Fail_Count_Chip"; - break; + return "Program_Fail_Count_Chip"; case 176: - name="Erase_Fail_Count_Chip"; - break; + return "Erase_Fail_Count_Chip"; case 177: - name="Wear_Leveling_Count"; - break; + return "Wear_Leveling_Count"; case 178: - name="Used_Rsvd_Blk_Cnt_Chip"; - break; + return "Used_Rsvd_Blk_Cnt_Chip"; case 179: - name="Used_Rsvd_Blk_Cnt_Tot"; - break; + return "Used_Rsvd_Blk_Cnt_Tot"; case 180: - name="Unused_Rsvd_Blk_Cnt_Tot"; - break; + return "Unused_Rsvd_Blk_Cnt_Tot"; case 181: - name="Program_Fail_Cnt_Total"; - break; + return "Program_Fail_Cnt_Total"; case 182: - name="Erase_Fail_Count_Total"; - break; + return "Erase_Fail_Count_Total"; case 183: - name="Runtime_Bad_Block"; - break; + return "Runtime_Bad_Block"; case 184: - name="End-to-End_Error"; - break; + return "End-to-End_Error"; case 187: - name="Reported_Uncorrect"; - break; + return "Reported_Uncorrect"; case 188: - name="Command_Timeout"; - break; + return "Command_Timeout"; case 189: - name="High_Fly_Writes"; - break; + return "High_Fly_Writes"; case 190: // Western Digital uses this for temperature. // It's identical to Attribute 194 except that it @@ -2036,217 +1982,107 @@ void ataPrintSmartAttribName(char * out, unsigned char id, const unsigned char * // is typically 55C. So if this attribute has failed // in the past, it indicates that the drive temp exceeded // 55C sometime in the past. - name="Airflow_Temperature_Cel"; - break; + return "Airflow_Temperature_Cel"; case 191: - name="G-Sense_Error_Rate"; - break; + return "G-Sense_Error_Rate"; case 192: - switch (val) { - case 1: - // Fujitsu - name="Emerg_Retract_Cycle_Ct"; - break; - default: - name="Power-Off_Retract_Count"; - break; - } - break; + return "Power-Off_Retract_Count"; case 193: - name="Load_Cycle_Count"; - break; + return "Load_Cycle_Count"; case 194: - switch (val){ - case 1: - // Samsung SV1204H with RK100-13 firmware - name="Temperature_Celsius_x10"; - break; - case 2: - // for disks with no temperature Attribute - name="Unknown_Attribute"; - break; - default: - name="Temperature_Celsius"; - break; - } - break; + return "Temperature_Celsius"; case 195: - // Fujitsu name="ECC_On_The_Fly_Count"; - name="Hardware_ECC_Recovered"; - break; + // Fujitsu: "ECC_On_The_Fly_Count"; + return "Hardware_ECC_Recovered"; case 196: - name="Reallocated_Event_Count"; - break; + return "Reallocated_Event_Count"; case 197: - switch (val) { - default: - name="Current_Pending_Sector"; - break; - case 1: - // Not reset after sector reallocation - name="Total_Pending_Sectors"; - break; - } - break; + return "Current_Pending_Sector"; case 198: - switch (val){ - default: - name="Offline_Uncorrectable"; - break; - case 1: - // Not reset after sector reallocation - name="Total_Offl_Uncorrectabl"/*e*/; - break; - case 2: - // Fujitsu - name="Offline_Scan_UNC_SectCt"; - break; - } - break; + return "Offline_Uncorrectable"; case 199: - name="UDMA_CRC_Error_Count"; - break; + return "UDMA_CRC_Error_Count"; case 200: - switch (val) { - case 1: - // Fujitsu MHS2020AT - name="Write_Error_Count"; - break; - default: - // Western Digital - name="Multi_Zone_Error_Rate"; - break; - } - break; + // Western Digital + return "Multi_Zone_Error_Rate"; case 201: - switch (val) { - case 1: - // Fujitsu - name="Detected_TA_Count"; - break; - default: - name="Soft_Read_Error_Rate"; - break; - } - break; + return "Soft_Read_Error_Rate"; case 202: // Fujitsu: "TA_Increase_Count" - name="Data_Address_Mark_Errs"; - break; + return "Data_Address_Mark_Errs"; case 203: // Fujitsu - name="Run_Out_Cancel"; + return "Run_Out_Cancel"; // Maxtor: ECC Errors - break; case 204: // Fujitsu: "Shock_Count_Write_Opern" - name="Soft_ECC_Correction"; - break; + return "Soft_ECC_Correction"; case 205: // Fujitsu: "Shock_Rate_Write_Opern" - name="Thermal_Asperity_Rate"; - break; + return "Thermal_Asperity_Rate"; case 206: // Fujitsu - name="Flying_Height"; - break; + return "Flying_Height"; case 207: // Maxtor - name="Spin_High_Current"; - break; + return "Spin_High_Current"; case 208: // Maxtor - name="Spin_Buzz"; - break; + return "Spin_Buzz"; case 209: // Maxtor - name="Offline_Seek_Performnce"; - break; + return "Offline_Seek_Performnce"; case 220: - switch (val) { - case 1: - name="Temperature_Celsius"; - break; - default: - name="Disk_Shift"; - break; - } - break; + return "Disk_Shift"; case 221: - name="G-Sense_Error_Rate"; - break; + return "G-Sense_Error_Rate"; case 222: - name="Loaded_Hours"; - break; + return "Loaded_Hours"; case 223: - name="Load_Retry_Count"; - break; + return "Load_Retry_Count"; case 224: - name="Load_Friction"; - break; + return "Load_Friction"; case 225: - switch (val) { - case 1: - // seen in Intel X25-E SSD - name="Host_Writes_Count"; - break; - default: - name="Load_Cycle_Count"; - break; - } - break; + return "Load_Cycle_Count"; case 226: - name="Load-in_Time"; - break; + return "Load-in_Time"; case 227: - name="Torq-amp_Count"; - break; + return "Torq-amp_Count"; case 228: - name="Power-off_Retract_Count"; - break; + return "Power-off_Retract_Count"; case 230: // seen in IBM DTPA-353750 - name="Head_Amplitude"; - break; + return "Head_Amplitude"; case 231: - name="Temperature_Celsius"; - break; + return "Temperature_Celsius"; case 232: // seen in Intel X25-E SSD - name="Available_Reservd_Space"; - break; + return "Available_Reservd_Space"; case 233: // seen in Intel X25-E SSD - name="Media_Wearout_Indicator"; - break; - case 240: - switch (val) { - case 1: - // seen in Fujitsu MHY2xxxBH - name="Transfer_Error_Rate"; - break; - default: - name="Head_Flying_Hours"; - break; - } + return "Media_Wearout_Indicator"; + case 240: + return "Head_Flying_Hours"; case 241: - name="Total_LBAs_Written"; - break; + return "Total_LBAs_Written"; case 242: - name="Total_LBAs_Read"; - break; + return "Total_LBAs_Read"; case 250: - name="Read_Error_Retry_Rate"; - break; + return "Read_Error_Retry_Rate"; case 254: - name="Free_Fall_Sensor"; - break; + return "Free_Fall_Sensor"; default: - name="Unknown_Attribute"; - break; + return "Unknown_Attribute"; } - sprintf(out,"%3hu %s",(short int)id,name); - return; +} + +// Get attribute name +std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs) +{ + if (!defs[id].name.empty()) + return defs[id].name; + else + return get_default_attr_name(id); } // Returns raw value of Attribute with ID==id. This will be in the @@ -2286,22 +2122,20 @@ int64_t ATAReturnAttributeRawValue(unsigned char id, const ata_smart_values * da // Return Temperature Attribute raw value selected according to possible // non-default interpretations. If the Attribute does not exist, return 0 -unsigned char ATAReturnTemperatureValue(const ata_smart_values * data, const unsigned char * defs) +unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs) { for (int i = 0; i < 3; i++) { static const unsigned char ids[3] = {194, 9, 220}; unsigned char id = ids[i]; - unsigned char select = (defs ? defs[id] : 0); - int64_t raw; unsigned temp; - if (!( (id == 194 && select <= 1) // ! -v 194,unknown - || (id == 9 && select == 2) // -v 9,temp - || (id == 220 && select == 1))) // -v 220,temp + const ata_attr_raw_format format = defs[id].raw_format; + if (!( (id == 194 && format == RAWFMT_DEFAULT) + || format == RAWFMT_TEMPMINMAX || format == RAWFMT_TEMP10X)) continue; - raw = ATAReturnAttributeRawValue(id, data); + int64_t raw = ATAReturnAttributeRawValue(id, data); if (raw < 0) continue; - temp = (unsigned short)raw; // ignore possible min/max values in high words - if (id == 194 && select == 1) // -v 194,10xCelsius + unsigned temp = (unsigned short)raw; // ignore possible min/max values in high words + if (format == RAWFMT_TEMP10X) // -v N,temp10x temp = (temp+5) / 10; if (!(0 < temp && temp <= 255)) continue; diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h index 7b18b5213..7c02c3a24 100644 --- a/smartmontools/atacmds.h +++ b/smartmontools/atacmds.h @@ -626,6 +626,64 @@ struct ata_selective_selftest_args : num_spans(0), pending_time(0), scan_after_select(0) { } }; +// Priority for vendor attribute defs +enum ata_vendor_def_prior +{ + PRIOR_DEFAULT, + PRIOR_DATABASE, + PRIOR_USER +}; + +// Raw attribute value print formats +enum ata_attr_raw_format +{ + RAWFMT_DEFAULT, + RAWFMT_RAW8, + RAWFMT_RAW16, + RAWFMT_RAW48, + RAWFMT_RAW16_OPT_RAW16, + RAWFMT_RAW16_OPT_AVG16, + RAWFMT_RAW24_RAW24, + RAWFMT_SEC2HOUR, + RAWFMT_MIN2HOUR, + RAWFMT_HALFMIN2HOUR, + RAWFMT_TEMPMINMAX, + RAWFMT_TEMP10X, +}; + +// Attribute flags +enum { + ATTRFLAG_INCREASING = 0x01 // Value not reset (for reallocated/pending counts) +}; + +// Vendor attribute display defs for all attribute ids +class ata_vendor_attr_defs +{ +public: + struct entry + { + std::string name; // Attribute name, empty for default + ata_attr_raw_format raw_format; // Raw value print format + ata_vendor_def_prior priority; // Setting priority + unsigned flags; // ATTRFLAG_* + + entry() + : raw_format(RAWFMT_DEFAULT), + priority(PRIOR_DEFAULT), + flags(0) + { } + }; + + entry & operator[](unsigned char id) + { return m_defs[id]; } + + const entry & operator[](unsigned char id) const + { return m_defs[id]; } + +private: + entry m_defs[256]; +}; + // Get information from drive int ataReadHDIdentity(ata_device * device, struct ata_identify_device *buf); @@ -741,15 +799,13 @@ int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest int TestTime(const ata_smart_values * data, int testtype); -// Prints the raw value (with appropriate formatting) into the -// character string out. -int64_t ataPrintSmartAttribRawValue(char *out, - const ata_smart_attribute * attribute, - const unsigned char * defs); +// Format attribute raw value. +std::string ata_format_attr_raw_value(const ata_smart_attribute & attribute, + const ata_vendor_attr_defs & defs); -// Prints Attribute Name for standard SMART attributes. Writes a -// 30 byte string with attribute name into output -void ataPrintSmartAttribName(char * out, unsigned char id, const unsigned char * definitions); +// Get attribute name +std::string ata_get_smart_attr_name(unsigned char id, + const ata_vendor_attr_defs & defs); // This checks the n'th attribute in the attribute list, NOT the // attribute with id==n. If the attribute does not exist, or the @@ -774,7 +830,7 @@ int64_t ATAReturnAttributeRawValue(unsigned char id, const ata_smart_values * da // Return Temperature Attribute raw value selected according to possible // non-default interpretations. If the Attribute does not exist, return 0 -unsigned char ATAReturnTemperatureValue(const ata_smart_values * data, const unsigned char * defs); +unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs); // This are the meanings of the Self-test failure checkpoint byte. @@ -788,14 +844,14 @@ const char *SelfTestFailureCodeName(unsigned char which); #define MAX_ATTRIBUTE_NUM 256 -// function to parse pairs like "9,minutes" or "220,temp". See end of -// extern.h for definition of defs[]. Returns 0 if pair recognized, -// else 1 if there is a problem. -int parse_attribute_def(const char * pair, unsigned char * defs); +// Parse vendor attribute display def (-v option). +// Return false on error. +bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs, + ata_vendor_def_prior priority); // Get ID and increase flag of current pending or offline // uncorrectable attribute. -unsigned char get_unc_attr_id(bool offline, const unsigned char * defs, +unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs, bool & increase); // Return a multiline string containing a list of valid arguments for diff --git a/smartmontools/ataprint.cpp b/smartmontools/ataprint.cpp index 78ad54945..a9511a115 100644 --- a/smartmontools/ataprint.cpp +++ b/smartmontools/ataprint.cpp @@ -778,12 +778,11 @@ static void PrintSmartConveyanceSelfTestPollingTime(const ata_smart_values * dat // onlyfailed=2: ones that are failed, or have failed with or without prefailure bit set static void PrintSmartAttribWithThres(const ata_smart_values * data, const ata_smart_thresholds_pvt * thresholds, - const unsigned char * attributedefs, + const ata_vendor_attr_defs & defs, int onlyfailed) { int needheader=1; - char rawstring[64]; - + // step through all vendor attributes for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const char *status; @@ -794,7 +793,6 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data, // thresholds page data to slip by) if (disk->id){ const char *type, *update; - char attributename[64]; // Don't report a failed attribute if its threshold is 0. // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing" @@ -829,30 +827,23 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data, else status=" -"; - // Print name of attribute - ataPrintSmartAttribName(attributename, disk->id, attributedefs); - pout("%-28s",attributename); - // printing line for each valid attribute type=ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)?"Pre-fail":"Old_age"; update=ATTRIBUTE_FLAGS_ONLINE(disk->flags)?"Always":"Offline"; - pout("0x%04x %.3d %.3d %.3d %-10s%-9s%-12s", - (int)disk->flags, (int)disk->current, (int)disk->worst, - (int)thre->threshold, type, update, status); + pout("%3d %-24s0x%04x %.3d %.3d %.3d %-10s%-9s%-12s%s\n", + disk->id, ata_get_smart_attr_name(disk->id, defs).c_str(), + (int)disk->flags, (int)disk->current, (int)disk->worst, + (int)thre->threshold, type, update, status, + ata_format_attr_raw_value(*disk, defs).c_str()); - // print raw value of attribute - ataPrintSmartAttribRawValue(rawstring, disk, attributedefs); - pout("%s\n", rawstring); - // Print a warning if there is inconsistency here and // threshold info is not empty. if (disk->id != thre->id && (thre->id || thre->threshold)) { - char atdat[64],atthr[64]; - ataPrintSmartAttribName(atdat, disk->id, attributedefs); - ataPrintSmartAttribName(atthr, thre->id, attributedefs); - pout("%-28s<== Data Page | WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",atdat); - pout("%-28s<== Threshold Page | INCONSISTENT IDENTITIES IN THE DATA\n",atthr); + pout("%3d %-24s<== Data Page | WARNING: PREVIOUS ATTRIBUTE HAS TWO\n", + disk->id, ata_get_smart_attr_name(disk->id, defs).c_str()); + pout("%3d %-24s<== Threshold Page | INCONSISTENT IDENTITIES IN THE DATA\n", + thre->id, ata_get_smart_attr_name(thre->id, defs).c_str()); } } } @@ -1757,11 +1748,10 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) } // Use preset vendor attribute options unless user has requested otherwise. - unsigned char attributedefs[256]; - memcpy(attributedefs, options.attributedefs, sizeof(attributedefs)); + ata_vendor_attr_defs attribute_defs = options.attribute_defs; unsigned char fix_firmwarebug = options.fix_firmwarebug; if (!options.ignore_presets) - apply_presets(&drive, attributedefs, fix_firmwarebug, options.fix_swapped_id); + apply_presets(&drive, attribute_defs, fix_firmwarebug, options.fix_swapped_id); // Print most drive identity information if requested bool known = false; @@ -1964,7 +1954,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) else { PRINT_ON(con); pout("Please note the following marginal Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 2); + PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2); } returnval|=FAILAGE; } @@ -1985,7 +1975,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) else { PRINT_ON(con); pout("Failed Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 1); + PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1); } } else @@ -2009,7 +1999,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) else { PRINT_ON(con); pout("Failed Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 1); + PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1); } } else { @@ -2020,7 +2010,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) else { PRINT_ON(con); pout("Please note the following marginal Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 2); + PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2); } returnval|=FAILAGE; } @@ -2041,7 +2031,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) // Print vendor-specific attributes if (options.smart_vendor_attrib) { PRINT_ON(con); - PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, + PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, (con->printing_switchable ? 2 : 0)); PRINT_OFF(con); } diff --git a/smartmontools/ataprint.h b/smartmontools/ataprint.h index a49389217..6c8c5eef2 100644 --- a/smartmontools/ataprint.h +++ b/smartmontools/ataprint.h @@ -26,7 +26,7 @@ #ifndef ATAPRINT_H_ #define ATAPRINT_H_ -#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.43 2009/07/07 19:28:29 chrfranke Exp $\n" +#define ATAPRINT_H_CVSID "$Id$\n" #include <vector> @@ -78,13 +78,7 @@ struct ata_print_options unsigned char fix_firmwarebug; // FIX_*, see atacmds.h bool fix_swapped_id; // Fix swapped ID strings returned by some buggy drivers - // The i'th entry in this array will modify the printed meaning of - // the i'th SMART attribute. The default definitions of the - // Attributes are obtained by having the array be all zeros. If - // attributedefs[i] is nonzero, it means that the i'th attribute has - // a non-default meaning. See the ataPrintSmartAttribName and - // and parse_attribute_def functions. - unsigned char attributedefs[256]; + ata_vendor_attr_defs attribute_defs; // -v options bool ignore_presets; // Ignore presets from drive database bool show_presets; // Show presets and exit @@ -114,7 +108,7 @@ struct ata_print_options ignore_presets(false), show_presets(false), powermode(0) - { memset(attributedefs, 0, sizeof(attributedefs)); } + { } }; int ataPrintMain(ata_device * device, const ata_print_options & options); diff --git a/smartmontools/knowndrives.cpp b/smartmontools/knowndrives.cpp index b2b86063c..50d853e4d 100644 --- a/smartmontools/knowndrives.cpp +++ b/smartmontools/knowndrives.cpp @@ -76,7 +76,7 @@ static const drive_settings builtin_knowndrives[] = { { "Intel X25-E SSD", "SSDSA2SH(032|064)G1.* INTEL", "", "", - "-v 225,hostwritescount" + "-v 225,raw48,Host_Writes_Count" }, { "Transcend Solid-State Drive", "TS(8|16|32|64|128)GSSD25-(M|S)", @@ -222,7 +222,7 @@ static const drive_settings builtin_knowndrives[] = { { "Fujitsu MHY2 BH series", "FUJITSU MHY2(04|06|08|10|12|16|20|25)0BH.*", "", "", - "-v 240,transfererrorrate" + "-v 240,raw48,Transfer_Error_Rate" }, { "Fujitsu MHW2 BH series", "FUJITSU MHW2(04|06|08|10|12|16)0BH.*", @@ -1450,7 +1450,8 @@ const drive_settings * lookup_drive(const char * model, const char * firmware) } // Parse '-v' and '-F' options in preset string, return false on error. -static bool parse_presets(const char * presets, unsigned char * opts, unsigned char & fix_firmwarebug) +static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs, + unsigned char & fix_firmwarebug) { for (int i = 0; ; ) { i += strspn(presets+i, " \t"); @@ -1460,14 +1461,9 @@ static bool parse_presets(const char * presets, unsigned char * opts, unsigned c if (!(sscanf(presets+i, "-%c %40[^ ]%n", &opt, arg, &len) >= 2 && len > 0)) return false; if (opt == 'v') { - // Parse "-v N,option" - unsigned char newopts[MAX_ATTRIBUTE_NUM] = {0, }; - if (parse_attribute_def(arg, newopts)) + // Parse "-v N,format[,name]" + if (!parse_attribute_def(arg, defs, PRIOR_DATABASE)) return false; - // Set only if not set by user - for (int j = 0; j < MAX_ATTRIBUTE_NUM; j++) - if (newopts[j] && !opts[j]) - opts[j] = newopts[j]; } else if (opt == 'F') { unsigned char fix; @@ -1524,19 +1520,16 @@ static int showonepreset(const drive_settings * dbentry) unsigned char fix_firmwarebug = 0; bool first_preset = true; if (*dbentry->presets) { - unsigned char opts[MAX_ATTRIBUTE_NUM] = {0,}; - if (!parse_presets(dbentry->presets, opts, fix_firmwarebug)) { + ata_vendor_attr_defs defs; + if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) { pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); errcnt++; } for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) { - char out[256]; - if (opts[i]) { - ataPrintSmartAttribName(out, i, opts); + if (defs[i].priority != PRIOR_DEFAULT) { // Use leading zeros instead of spaces so that everything lines up. - out[0] = (out[0] == ' ') ? '0' : out[0]; - out[1] = (out[1] == ' ') ? '0' : out[1]; - pout("%-*s %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", out); + pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", + i, ata_get_smart_attr_name(i, defs).c_str()); first_preset = false; } } @@ -1664,7 +1657,7 @@ void show_presets(const ata_identify_device * drive, bool fix_swapped_id) // (if any) for the given drive in knowndrives[]. Values that have // already been set in opts will not be changed. Returns false if drive // not recognized. -bool apply_presets(const ata_identify_device *drive, unsigned char * opts, +bool apply_presets(const ata_identify_device *drive, ata_vendor_attr_defs & defs, unsigned char & fix_firmwarebug, bool fix_swapped_id) { // get the drive's model/firmware strings @@ -1679,7 +1672,7 @@ bool apply_presets(const ata_identify_device *drive, unsigned char * opts, if (*dbentry->presets) { // Apply presets - if (!parse_presets(dbentry->presets, opts, fix_firmwarebug)) + if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); } return true; @@ -1899,8 +1892,8 @@ static bool parse_drive_database(parse_ptr src, drive_database & db, const char break; case 4: if (!token.value.empty()) { - unsigned char opts[MAX_ATTRIBUTE_NUM] = {0, }; unsigned char fix = 0; - if (!parse_presets(token.value.c_str(), opts, fix)) { + ata_vendor_attr_defs defs; unsigned char fix = 0; + if (!parse_presets(token.value.c_str(), defs, fix)) { pout("%s(%d): Syntax error in preset option string\n", path, token.line); ok = false; } diff --git a/smartmontools/knowndrives.h b/smartmontools/knowndrives.h index 3908e40f9..65f926f13 100644 --- a/smartmontools/knowndrives.h +++ b/smartmontools/knowndrives.h @@ -21,7 +21,7 @@ #ifndef KNOWNDRIVES_H_ #define KNOWNDRIVES_H_ -#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h,v 1.23 2009/04/16 21:24:08 chrfranke Exp $\n" +#define KNOWNDRIVES_H_CVSID "$Id$\n" /* Structure used to store settings for specific drives in knowndrives[]. The * elements are used in the following ways: @@ -69,7 +69,7 @@ int showmatchingpresets(const char *model, const char *firmware); // (if any) for the given drive in knowndrives[]. Values that have // already been set in opts will not be changed. Also sets options in // con. Returns false if drive not recognized. -bool apply_presets(const ata_identify_device * drive, unsigned char * opts, +bool apply_presets(const ata_identify_device * drive, ata_vendor_attr_defs & defs, unsigned char & fix_firmwarebug, bool fix_swapped_id); // Read drive database from file. diff --git a/smartmontools/smartctl.cpp b/smartmontools/smartctl.cpp index 5e9f89f6b..93ba92894 100644 --- a/smartmontools/smartctl.cpp +++ b/smartmontools/smartctl.cpp @@ -539,7 +539,7 @@ const char * parse_options(int argc, char** argv, create_vendor_attribute_arg_list().c_str()); EXIT(0); } - if (parse_attribute_def(optarg, ataopts.attributedefs)) + if (!parse_attribute_def(optarg, ataopts.attribute_defs, PRIOR_USER)) badarg = true; break; case 'P': diff --git a/smartmontools/smartd.cpp b/smartmontools/smartd.cpp index b712f6702..18d23085f 100644 --- a/smartmontools/smartd.cpp +++ b/smartmontools/smartd.cpp @@ -283,8 +283,7 @@ struct dev_config attribute_flags monitor_attr_flags; // MONITOR_* flags for each attribute - // TODO: Encapsulate, add get/set functions - unsigned char attributedefs[256]; // -v options, see end of extern.h for def + ata_vendor_attr_defs attribute_defs; // -v options dev_config(); }; @@ -315,7 +314,6 @@ dev_config::dev_config() curr_pending_incr(false), offl_pending_incr(false), curr_pending_set(false), offl_pending_set(false) { - memset(attributedefs, 0, sizeof(attributedefs)); } @@ -1613,7 +1611,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name); else { // do whatever applypresets decides to do. - if (!apply_presets(&drive, cfg.attributedefs, cfg.fix_firmwarebug, fix_swapped_id)) + if (!apply_presets(&drive, cfg.attribute_defs, cfg.fix_firmwarebug, fix_swapped_id)) PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name); else PrintOut(LOG_INFO, "Device: %s, found in smartd database.\n", name); @@ -1621,10 +1619,10 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade // Set default '-C 197[+]' if no '-C ID' is specified. if (!cfg.curr_pending_set) - cfg.curr_pending_id = get_unc_attr_id(false, cfg.attributedefs, cfg.curr_pending_incr); + cfg.curr_pending_id = get_unc_attr_id(false, cfg.attribute_defs, cfg.curr_pending_incr); // Set default '-U 198[+]' if no '-U ID' is specified. if (!cfg.offl_pending_set) - cfg.offl_pending_id = get_unc_attr_id(true, cfg.attributedefs, cfg.offl_pending_incr); + cfg.offl_pending_id = get_unc_attr_id(true, cfg.attribute_defs, cfg.offl_pending_incr); // If requested, show which presets would be used for this drive if (cfg.showpresets) { @@ -1725,7 +1723,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade } if ( (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) - && !ATAReturnTemperatureValue(&state.smartval, cfg.attributedefs)) { + && !ata_return_temperature_value(&state.smartval, cfg.attribute_defs)) { PrintOut(LOG_CRIT, "Device: %s, can't monitor Temperature, ignoring -W Directive\n", name); cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0; } @@ -2668,7 +2666,7 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device // check temperature limits if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) - CheckTemperature(cfg, state, ATAReturnTemperatureValue(&curval, cfg.attributedefs), 0); + CheckTemperature(cfg, state, ata_return_temperature_value(&curval, cfg.attribute_defs), 0); if (cfg.usagefailed || cfg.prefail || cfg.usage) { @@ -2684,15 +2682,10 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device // are we ignoring failures of this attribute? att *= -1; if (!cfg.monitor_attr_flags.is_set(att, MONITOR_IGN_FAILUSE)) { - char attname[64], *loc=attname; - - // get attribute name & skip white space - ataPrintSmartAttribName(loc, att, cfg.attributedefs); - while (*loc && *loc==' ') loc++; - // warning message - PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc); - MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %s.", name, loc); + std::string attrname = ata_get_smart_attr_name(att, cfg.attribute_defs); + PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", name, att, attrname.c_str()); + MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", name, att, attrname.c_str()); state.must_write = true; } } @@ -2719,29 +2712,23 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device && !cfg.monitor_attr_flags.is_set(id, MONITOR_RAW)) continue; - // get attribute name, skip spaces - char attname[64], *loc = attname; - ataPrintSmartAttribName(loc, id, cfg.attributedefs); - while (*loc && *loc==' ') - loc++; + // get attribute name + std::string attrname = ata_get_smart_attr_name(id, cfg.attribute_defs); // has the user asked for us to print raw values? - char newrawstring[64], oldrawstring[64]; + std::string newraw, oldraw; if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) { // get raw values (as a string) and add to printout - char rawstring[64]; - ataPrintSmartAttribRawValue(rawstring, curval.vendor_attributes+i, cfg.attributedefs); - sprintf(newrawstring, " [Raw %s]", rawstring); - ataPrintSmartAttribRawValue(rawstring, state.smartval.vendor_attributes+i, cfg.attributedefs); - sprintf(oldrawstring, " [Raw %s]", rawstring); + newraw = strprintf(" [Raw %s]", + ata_format_attr_raw_value(curval.vendor_attributes[i], cfg.attribute_defs).c_str()); + oldraw = strprintf(" [Raw %s]", + ata_format_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs).c_str()); } - else - newrawstring[0]=oldrawstring[0]='\0'; // Format message - std::string msg = strprintf("Device: %s, SMART %s Attribute: %s changed from %d%s to %d%s", - name, (delta.prefail ? "Prefailure" : "Usage"), loc, - delta.oldval, oldrawstring, delta.newval, newrawstring); + std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %d%s to %d%s", + name, (delta.prefail ? "Prefailure" : "Usage"), id, attrname.c_str(), + delta.oldval, oldraw.c_str(), delta.newval, newraw.c_str()); // Report this change as critical ? if ( (delta.newval != delta.oldval && cfg.monitor_attr_flags.is_set(id, MONITOR_AS_CRIT)) @@ -3408,7 +3395,7 @@ static int ParseToken(char * token, dev_config & cfg) // non-default vendor-specific attribute meaning if (!(arg=strtok(NULL,delim))) { missingarg = 1; - } else if (parse_attribute_def(arg, cfg.attributedefs)) { + } else if (!parse_attribute_def(arg, cfg.attribute_defs, PRIOR_USER)) { badarg = 1; } break; -- GitLab