diff --git a/cmdline/device.c b/cmdline/device.c index 7fec5828..88783468 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -393,21 +393,28 @@ static void state_smart(int verbose, unsigned n, tommy_list* low) else if (flag & SMARTCTL_FLAG_ERROR_LOGGED) printf(" ERROR"); else if (flag & SMARTCTL_FLAG_OPEN) - printf(" n/o"); + printf(" n/a"); else if (flag & SMARTCTL_FLAG_COMMAND) - printf(" n/c"); + printf(" n/a"); else if (devinfo->smart[SMART_ERROR] == 0) printf(" 0"); else printf(" -"); - afr = smart_afr(devinfo->smart); + /* if SSD, skip AFR estimation as data is from not SSD disks */ + if (devinfo->smart[SMART_ROTATION_RATE] == 0) { + afr = 0; - /* use only afr of disks in the array */ - if (devinfo->parent != 0 || !have_parent) - array_failure_rate += afr; + printf(" -"); + } else { + afr = smart_afr(devinfo->smart); - printf("%4.0f%%", poisson_prob_n_or_more_failures(afr, 1) * 100); + /* use only afr of disks in the array */ + if (devinfo->parent != 0 || !have_parent) + array_failure_rate += afr; + + printf("%4.0f%%", poisson_prob_n_or_more_failures(afr, 1) * 100); + } if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED) printf(" %2.1f", devinfo->smart[SMART_SIZE] / 1E12); @@ -446,6 +453,8 @@ static void state_smart(int verbose, unsigned n, tommy_list* low) fprintf(stdlog, "attr:%s:size:%" PRIu64 "\n", devinfo->file, devinfo->smart[SMART_SIZE]); if (devinfo->smart[SMART_ERROR] != SMART_UNASSIGNED) fprintf(stdlog, "attr:%s:error:%" PRIu64 "\n", devinfo->file, devinfo->smart[SMART_ERROR]); + if (devinfo->smart[SMART_ROTATION_RATE] != SMART_UNASSIGNED) + fprintf(stdlog, "attr:%s:rotationrate:%" PRIu64 "\n", devinfo->file, devinfo->smart[SMART_ROTATION_RATE]); } printf("\n"); @@ -459,8 +468,8 @@ static void state_smart(int verbose, unsigned n, tommy_list* low) fprintf(stdlog, "summary:array_failure:%g:%g\n", array_failure_rate, p_at_least_one_failure); /* |<##################################################################72>|####80>| */ - printf("The FP column is the probability (in percentage) that the disk is going\n"); - printf("to fail in the next year.\n"); + printf("The FP column is the estimated probability (in percentage) that the disk\n"); + printf("is going to fail in the next year.\n"); printf("\n"); printf("Probability that one disk is going to fail in the next year is: %.0f%%\n", p_at_least_one_failure * 100); diff --git a/cmdline/portable.h b/cmdline/portable.h index 98e1f31f..2a2b67f6 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -313,16 +313,17 @@ int exit_failure; int randomize(void* ptr, size_t size); /** - * SMART attributes. - */ -#define SMART_COUNT (256+3) - -/** - * Additional info attributes. + * Additional SMART attributes. */ #define SMART_ERROR 256 /**< ATA Error count. */ #define SMART_SIZE 257 /**< Size in bytes. */ -#define SMART_FLAGS 258 /**< Flags returned by smartctl. */ +#define SMART_ROTATION_RATE 258 /**< Rotation speed. 0 for SSD. */ +#define SMART_FLAGS 259 /**< Flags returned by smartctl. */ + +/** + * SMART attributes count. + */ +#define SMART_COUNT 260 /** * Flags returned by smartctl. diff --git a/cmdline/support.c b/cmdline/support.c index 6019d6db..10a23daa 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -397,6 +397,28 @@ char* strdup_nofail(const char* str) /****************************************************************************/ /* smartctl */ +/** + * Matches a string with the specified pattern. + * Like sscanf() a space match any sequence of spaces. + * Returns 0 if it matches. + */ +static int smatch(const char* str, const char* pattern) +{ + while (*pattern) { + if (isspace(*pattern)) { + ++pattern; + while (isspace(*str)) + ++str; + } else if (*pattern == *str) { + ++pattern; + ++str; + } else + return -1; + } + + return 0; +} + int smartctl_attribute(FILE* f, uint64_t* smart, char* serial) { unsigned i; @@ -427,13 +449,16 @@ int smartctl_attribute(FILE* f, uint64_t* smart, char* serial) if (*s == 0) { inside = 0; - } else if (strncmp(s, "ID#", 3) == 0) { + } else if (smatch(s, "ID#") == 0) { inside = 1; - } else if (strncmp(s, "No Errors Logged", 16) == 0) { + } else if (smatch(s, "No Errors Logged") == 0) { smart[SMART_ERROR] = 0; } else if (sscanf(s, "ATA Error Count: %" SCNu64, &raw) == 1) { smart[SMART_ERROR] = raw; } else if (sscanf(s, "Serial Number: %63s", serial) == 1) { + } else if (smatch(s, "Rotation Rate: Solid State") == 0) { + smart[SMART_ROTATION_RATE] = 0; + } else if (sscanf(s, "Rotation Rate: %" SCNu64, &smart[SMART_ROTATION_RATE]) == 1) { } else if (sscanf(s, "User Capacity: %63s", attr) == 1) { smart[SMART_SIZE] = 0; for (i = 0; attr[i]; ++i) {