OS/2, eCS & ArcaOS - Technical > Utilities
graphic interface for smartahci
Doug Bissett:
I will comment here, that I do not trust anything that, so called, smart monitoring tells me. I have (had) one disk that never showed any problem, but just plain wouldn't work because of errors. I have another disk, that has been telling me that total failure has already happened, but it continues to work, with no problems, after 10 years (I do need to turn off the BIOS checking, or it refuses to use the disk). I had another one, that told me that all was well, and it became unusable 3 days later.
Use it if you want to, but be very wary of what it tells you. Better to spend your time doing backups.
ivan:
I agree with you Doug especially about backups. If used properly the SMART information can be useful (in the graphic the attributes marked with * are the ones to watch. I have had a couple of disks that worked but it took them up to 5 minutes to spin up so they got pensioned off before the stopped spinning at all. Relocated sector count is another one to watch because disks only have a limited number of sectors to relocate and when they are used up problems start.
SMART data isn't for general use, you have to know what you are reading and how it interacts with the disk electronics firmware.
Dave Yeo:
--- Quote from: ivan on October 30, 2019, 05:21:01 pm ---OK, I have got a little further, I can now get the main information by using smartahci -A hd1 > some text file which gives
...
Which leaves me wondering hoe to get a graphics display like the attachment.
Any Ideas?
--- End quote ---
Might be as simple as setting the correct terminal (doubtful as I don't see any ansi) or more likely, need compiling with ansi support. I don't have an ahci adapter so can't test but assuming it shares the same source as smartmon, it should be able to output the correct ansi.
RickCHodgin:
--- Quote from: ivan on October 30, 2019, 05:21:01 pm ---OK, I have got a little further, I can now get the main information by using smartahci -A hd1 > some text file which gives
--- Code: ---=== START OF READ SMART DATA SECTION ===
SMART Attributes Data Structure revision number: 10
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
1 Raw_Read_Error_Rate 0x000f 116 099 006 Pre-fail Always - 109444736
3 Spin_Up_Time 0x0003 098 097 000 Pre-fail Always - 0
4 Start_Stop_Count 0x0032 100 100 020 Old_age Always - 26
5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always - 0
7 Seek_Error_Rate 0x000f 076 060 030 Pre-fail Always - 47200953
9 Power_On_Hours 0x0032 094 094 000 Old_age Always - 5878
10 Spin_Retry_Count 0x0013 100 100 097 Pre-fail Always - 0
12 Power_Cycle_Count 0x0032 100 100 020 Old_age Always - 29
183 Runtime_Bad_Block 0x0032 100 100 000 Old_age Always - 0
184 End-to-End_Error 0x0032 100 100 099 Old_age Always - 0
187 Reported_Uncorrect 0x0032 100 100 000 Old_age Always - 0
188 Command_Timeout 0x0032 100 100 000 Old_age Always - 1
189 High_Fly_Writes 0x003a 100 100 000 Old_age Always - 0
190 Airflow_Temperature_Cel 0x0022 062 051 045 Old_age Always - 38 (Min/Max 24/48)
191 G-Sense_Error_Rate 0x0032 100 100 000 Old_age Always - 0
192 Power-Off_Retract_Count 0x0032 100 100 000 Old_age Always - 20
193 Load_Cycle_Count 0x0032 093 093 000 Old_age Always - 14984
194 Temperature_Celsius 0x0022 038 049 000 Old_age Always - 38 (0 14 0 0 0)
197 Current_Pending_Sector 0x0012 100 100 000 Old_age Always - 0
198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 0
199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 0
240 Head_Flying_Hours 0x0000 100 253 000 Old_age Offline - 1021 (61 65 0)
241 Total_LBAs_Written 0x0000 100 253 000 Old_age Offline - 995271562
242 Total_LBAs_Read 0x0000 100 253 000 Old_age Offline - 880064779
--- End code ---
Which leaves me wondering hoe to get a graphics display like the attachment.
Any Ideas?
--- End quote ---
It looks like the Worst column is used for the indicator. When it's 100, it has red, yellow, yellow, then full greens. When it was 99, it drops down one, same with 92. When it was 82 or 75, it had fewer greens.
It seems to just be a projection of that value relative to what it should be. Some values seem to be up to 100. Others 200. Others 255.
Something like (off the top of my head, untested):
--- Code: ---char ansi_red[] = "whatever the code is for ANSI red";
char ansi_yellow[] = "whatever the code is for ANSI yellow";
char ansi_green[] = "whatever the code is for ANSI green";
char ansi_normal[] = "whatever the code is for ANSI normal";
// See http://ascii-table.com/ansi-escape-sequences.php
// Possibly the codes are ... don't know, haven't used them since DOS days in 90s:
// ansi_red = "\033[1;31;40m";
// ansi_yellow = "\033[1;33;40m";
// ansi_green = "\033[1;32;40m";
// ansi_normal = "\033[0;37;40m";
char* get_indicator(int value, int max_value, int& len)
{
int s, d;
char* ind;
// Make sure the parameters are in range
max_value = max(max_value, 1);
value = min(value, max_value);
// Get the length we'll need
len = (int)(10.0f * (float)value / (float)max_value);
// Allocate the maximum length we'll need for the indicator
ind = malloc( ((len >= 1) ? sizeof(ansi_red) : 0)
+ ((len >= 2) ? sizeof(ansi_yellow) : 0)
+ ((len >= 4) ? sizeof(ansi_green) : 0)
+ len
+ sizeof(ansi_normal) + 1 );
// Render it in ANSI
for (s = 0, d = 0; s < len; ++s)
{
// Add any ANSI codes:
if (s == 0)
{
// Add red
memcpy(ind + d, ansi_red, sizeof(ansi_red) - 1);
d += sizeof(ansi_red) - 1;
} else if (s == 1) {
// Add yellow
memcpy(ind + d, ansi_yellow, sizeof(ansi_yellow) - 1);
d += sizeof(ansi_yellow) - 1;
} else if (s == 3) {
// Add green
memcpy(ind + d, ansi_green, sizeof(ansi_green) - 1);
d += sizeof(ansi_green) - 1;
}
// Store the thick hyphen character
ind[d++] = 22;
}
// Add the trailing restore to normal coloring
memcpy(ind + d, ansi_normal, sizeof(ansi_normal) - 1);
d += sizeof(ansi_normal) - 1;
ind[d] = 0;
// Return our result
return ind;
// Note: len is updated to the number of thick hyphen characters to be displayed, not the string length
}
--- End code ---
If you are able to parse that data in raw text content, you could generate the display using something like ANSI escape codes and the ASCII 22 character. Or paint it on the terminal using color attributes. In either case, something like the above should work.
Make sure you free() the return value later.
RickCHodgin:
--- Quote from: Rick C. Hodgin on October 31, 2019, 02:42:29 am ---It looks like the Worst column is used for the indicator. When it's 100, it has red, yellow, yellow, then full greens. When it was 99, it drops down one, same with 92. When it was 82 or 75, it had fewer greens.
It seems to just be a projection of that value relative to what it should be. Some values seem to be up to 100. Others 200. Others 255.
Something like (off the top of my head, untested):
--- Code: ---// Snip
--- End code ---
If you are able to parse that data in raw text content, you could generate the display using something like ANSI escape codes and the ASCII 22 character. Or paint it on the terminal using color attributes. In either case, something like the above should work.
Make sure you free() the return value later.
--- End quote ---
Here's an actual program that displays some colorize results. It doesn't handle the ID#... header line properly, but it does demonstrate the general idea.
--- Code: ---// Set your font small enough so you can see the screen
// [C:\] mode 120,40
// Compiled in Borland C++ for OS/2 Version 2.0
#include <os2.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#define max(a,b) ((a) >= (b) ? (a) : (b))
#define min(a,b) ((a) <= (b) ? (a) : (b))
char text[] = " === START OF READ SMART DATA SECTION ===\r\n"
"SMART Attributes Data Structure revision number: 10\r\n"
"Vendor Specific SMART Attributes with Thresholds:\r\n"
/* 111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999 */
/* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 */
"ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE\r\n"
" 1 Raw_Read_Error_Rate 0x000f 116 099 006 Pre-fail Always - 109444736\r\n"
" 3 Spin_Up_Time 0x0003 098 097 000 Pre-fail Always - 0\r\n"
" 4 Start_Stop_Count 0x0032 100 100 020 Old_age Always - 26\r\n"
" 5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always - 0\r\n"
" 7 Seek_Error_Rate 0x000f 076 060 030 Pre-fail Always - 47200953\r\n"
" 9 Power_On_Hours 0x0032 094 094 000 Old_age Always - 5878\r\n"
" 10 Spin_Retry_Count 0x0013 100 100 097 Pre-fail Always - 0\r\n"
" 12 Power_Cycle_Count 0x0032 100 100 020 Old_age Always - 29\r\n"
"183 Runtime_Bad_Block 0x0032 100 100 000 Old_age Always - 0\r\n"
"184 End-to-End_Error 0x0032 100 100 099 Old_age Always - 0\r\n"
"187 Reported_Uncorrect 0x0032 100 100 000 Old_age Always - 0\r\n"
"188 Command_Timeout 0x0032 100 100 000 Old_age Always - 1\r\n"
"189 High_Fly_Writes 0x003a 100 100 000 Old_age Always - 0\r\n"
"190 Airflow_Temperature_Cel 0x0022 062 051 045 Old_age Always - 38 (Min/Max 24/48)\r\n"
"191 G-Sense_Error_Rate 0x0032 100 100 000 Old_age Always - 0\r\n"
"192 Power-Off_Retract_Count 0x0032 100 100 000 Old_age Always - 20\r\n"
"193 Load_Cycle_Count 0x0032 093 093 000 Old_age Always - 14984\r\n"
"194 Temperature_Celsius 0x0022 038 049 000 Old_age Always - 38 (0 14 0 0 0)\r\n"
"197 Current_Pending_Sector 0x0012 100 100 000 Old_age Always - 0\r\n"
"198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 0\r\n"
"199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 0\r\n"
"240 Head_Flying_Hours 0x0000 100 253 000 Old_age Offline - 1021 (61 65 0)\r\n"
"241 Total_LBAs_Written 0x0000 100 253 000 Old_age Offline - 995271562\r\n"
"242 Total_LBAs_Read 0x0000 100 253 000 Old_age Offline - 880064779\r\n";
// See http://ascii-table.com/ansi-escape-sequences.php
char ansi_red[] = "\033[1;31;40m";
char ansi_yellow[] = "\033[1;33;40m";
char ansi_green[] = "\033[1;32;40m";
char ansi_normal[] = "\033[0;37;40m";
char* get_indicator(int value, int max_value)
{
int s, d, len;
char* ind;
// Make sure the parameters are in range
max_value = max(max_value, 1);
value = min(value, max_value);
// Get the length we'll need
len = (int)(10.0f * (float)value / (float)max_value);
// Allocate the maximum length we'll need for the indicator
ind = (char*)malloc( ((len >= 1) ? sizeof(ansi_red) : 0)
+ ((len >= 2) ? sizeof(ansi_yellow) : 0)
+ ((len >= 4) ? sizeof(ansi_green) : 0)
+ 10
+ sizeof(ansi_normal) + 1 );
// Render it in ANSI
for (s = 0, d = 0; s < len; ++s)
{
// Add any ANSI codes:
if (s == 0)
{
// Add red
memcpy(ind + d, ansi_red, sizeof(ansi_red) - 1);
d += sizeof(ansi_red) - 1;
} else if (s == 1) {
// Add yellow
memcpy(ind + d, ansi_yellow, sizeof(ansi_yellow) - 1);
d += sizeof(ansi_yellow) - 1;
} else if (s == 3) {
// Add green
memcpy(ind + d, ansi_green, sizeof(ansi_green) - 1);
d += sizeof(ansi_green) - 1;
}
// Store the thick hyphen character
ind[d++] = 22;
}
// Add the trailing restore to normal coloring
memcpy(ind + d, ansi_normal, sizeof(ansi_normal) - 1);
d += sizeof(ansi_normal) - 1;
// Add in any trailing spaces
for ( ; s < 10; ++s)
ind[d++] = 32;
// NULL terminate and return
ind[d] = 0;
return ind;
}
int verify_hex(char* p, int len)
{
int i;
char c;
// Must begin with 0x
if (!memicmp(p, "0x", 2) == 0)
return 0;
// Every character must be 0_9a_fA_F
for (i = 2; i < len; ++i)
{
c = p[i];
if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
return 0;
}
// It's hex
return 1;
}
int verify_dec(char* p, int len)
{
int i;
// Every character must be 0_9
for (i = 0; i < len; ++i)
{
if (p[i] < '0' || p[i] > '9')
return 0;
}
// It's dec
return 1;
}
int display_line(int tnOffset)
{
int lnLength, lnValue, lnWorst;
int llTest1, llTest2, llTest3, llTest4;
char c;
char* p;
char* p2;
// Find out where this line ends
for (lnLength = 0, p = text + tnOffset; *p != 0; ++lnLength, ++p)
{
// Is it CR or LF?
if (*p == 13 || *p == 10)
{
// We're done here
break;
}
}
// Verify the signatures
llTest1 = verify_hex(text + tnOffset + 28, 6); // hex at 28,6 flag
llTest2 = verify_dec(text + tnOffset + 37, 3); // dec at 37,3 value
llTest3 = verify_dec(text + tnOffset + 43, 3); // dec at 43,3 worst
llTest4 = verify_dec(text + tnOffset + 49, 3); // dec at 49,3 thresh
if (llTest1 && llTest2 && llTest3 && llTest4)
{
// It's an indicator line
// Print up to the worst part
p2 = text + tnOffset + 43;
c = *p2;
*p2 = 0;
printf("%s", text + tnOffset);
*p2 = c;
// Grab the value
lnValue = 100; // assume 100 atoi(text + tnOffset + 37);
lnWorst = atoi(text + tnOffset + 43);
// Print the indicator
printf("%s", (p2 = get_indicator(lnWorst, lnValue)));
free(p2);
// Print the trailing part
c = *p;
*p = 0;
printf("%s\n", text + tnOffset + 48);
*p = c;
} else {
// Just a regular line
c = *p;
*p = 0;
printf("%s\n", text + tnOffset);
*p = c;
}
// Skip past any CR/LF combos
for ( ; *p != 0; ++lnLength)
{
c = text[tnOffset + lnLength];
if (c != 13 && c != 10)
break;
}
// All done
return lnLength;
}
int main(int argc, char* argv[])
{
int lnI;
// Code could be added here to read a file from the command
// line and load into char* text, rather than using the hard-coded
// example. It could also be used to read from STDIN so it can
// be piped to as in smartdrv > colorize.
// For illustration purposes only. Should be modified and extended if used.
// Display each line
for (lnI = 0; text[lnI] != 0; )
lnI += display_line(lnI);
return 0;
}
--- End code ---
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version