OS/2, eCS & ArcaOS - Technical > Utilities

graphic interface for smartahci

<< < (2/8) > >>

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