From 2735fd3198ffc5432b6fb807c4017deb35d401de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 19 Mar 2009 01:10:43 +0100 Subject: add new API sk_disk_smart_get_overall() --- atasmart.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- atasmart.h | 18 ++++++++++++ 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/atasmart.c b/atasmart.c index c822fa9..bab35dd 100644 --- a/atasmart.c +++ b/atasmart.c @@ -1361,7 +1361,6 @@ const char* sk_smart_attribute_unit_to_string(SkSmartAttributeUnit unit) { return _P(map[unit]); } - struct attr_helper { uint64_t *value; SkBool found; @@ -1386,7 +1385,6 @@ static void temperature_cb(SkDisk *d, const SkSmartAttributeParsedData *a, struc int sk_disk_smart_get_temperature(SkDisk *d, uint64_t *kelvin) { struct attr_helper ah; - int r; assert(d); assert(kelvin); @@ -1394,8 +1392,8 @@ int sk_disk_smart_get_temperature(SkDisk *d, uint64_t *kelvin) { ah.found = FALSE; ah.value = kelvin; - if ((r = sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) temperature_cb, &ah)) < 0) - return r; + if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) temperature_cb, &ah) < 0) + return -1; if (!ah.found) { errno = ENOENT; @@ -1424,7 +1422,6 @@ static void power_on_cb(SkDisk *d, const SkSmartAttributeParsedData *a, struct a int sk_disk_smart_get_power_on(SkDisk *d, uint64_t *mseconds) { struct attr_helper ah; - int r; assert(d); assert(mseconds); @@ -1432,8 +1429,8 @@ int sk_disk_smart_get_power_on(SkDisk *d, uint64_t *mseconds) { ah.found = FALSE; ah.value = mseconds; - if ((r = sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) power_on_cb, &ah)) < 0) - return r; + if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) power_on_cb, &ah) < 0) + return -1; if (!ah.found) { errno = ENOENT; @@ -1475,7 +1472,6 @@ static void pending_cb(SkDisk *d, const SkSmartAttributeParsedData *a, struct at int sk_disk_smart_get_bad(SkDisk *d, uint64_t *sectors) { struct attr_helper ah1, ah2; uint64_t sectors1, sectors2; - int r; assert(d); assert(sectors); @@ -1483,14 +1479,14 @@ int sk_disk_smart_get_bad(SkDisk *d, uint64_t *sectors) { ah1.found = FALSE; ah1.value = §ors1; - if ((r = sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) reallocated_cb, &ah1)) < 0) - return r; + if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) reallocated_cb, &ah1) < 0) + return -1; ah2.found = FALSE; ah2.value = §ors2; - if ((r = sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) pending_cb, &ah2)) < 0) - return r; + if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) pending_cb, &ah2) < 0) + return -1; if (!ah1.found && !ah2.found) { errno = ENOENT; @@ -1507,6 +1503,64 @@ int sk_disk_smart_get_bad(SkDisk *d, uint64_t *sectors) { return 0; } +const char* sk_smart_overall_to_string(SkSmartOverall overall) { + + /* %STRINGPOOLSTART% */ + const char * const map[] = { + [SK_SMART_OVERALL_GOOD] = "GOOD", + [SK_SMART_OVERALL_BAD_STATUS] = "BAD_STATUS", + [SK_SMART_OVERALL_BAD_ATTRIBUTE] = "BAD_ATTRIBUTE", + [SK_SMART_OVERALL_BAD_SECTOR] = "BAD_SECTOR" + }; + /* %STRINGPOOLSTOP% */ + + if (overall >= _SK_SMART_OVERALL_MAX) + return NULL; + + return _P(map[overall]); +} + +static void bad_attribute_cb(SkDisk *d, const SkSmartAttributeParsedData *a, SkBool *good) { + if (a->good_valid && !a->good) + *good = FALSE; +} + +int sk_disk_smart_get_overall(SkDisk *d, SkSmartOverall *overall) { + SkBool good; + uint64_t sectors; + + assert(d); + assert(overall); + + if (sk_disk_smart_status(d, &good) < 0) + return -1; + + if (!good) { + *overall = SK_SMART_OVERALL_BAD_STATUS; + return 0; + } + + if (sk_disk_smart_get_bad(d, §ors) < 0) { + if (errno != ENOENT) + return -1; + } else if (sectors > 0) { + *overall = SK_SMART_OVERALL_BAD_SECTOR; + return 0; + } + + good = TRUE; + if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) bad_attribute_cb, &good) < 0) + return -1; + + if (!good) { + *overall = SK_SMART_OVERALL_BAD_ATTRIBUTE; + return 0; + } + + *overall = SK_SMART_OVERALL_GOOD; + return 0; +} + static char* print_name(char *s, size_t len, uint8_t id, const char *k) { if (k) @@ -1649,6 +1703,7 @@ int sk_disk_dump(SkDisk *d) { ret >= 0 ? yes_no(awake) : "unknown"); if (disk_smart_is_available(d)) { + SkSmartOverall overall; const SkSmartParsedData *spd; SkBool good; char pretty[32]; @@ -1657,7 +1712,7 @@ int sk_disk_dump(SkDisk *d) { if ((ret = sk_disk_smart_status(d, &good)) < 0) return ret; - printf("Disk Health Good: %s\n", + printf("SMART Disk Health Good: %s\n", yes_no(good)); if ((ret = sk_disk_smart_read_data(d)) < 0) @@ -1692,7 +1747,10 @@ int sk_disk_dump(SkDisk *d) { if (sk_disk_smart_get_bad(d, &value) < 0) printf("Bad Sectors: %s\n", strerror(errno)); else - printf("Bad Sectors: %s\n", print_value(pretty, sizeof(pretty), value, SK_SMART_ATTRIBUTE_UNIT_SECTORS)); + printf("%sBad Sectors: %s%s\n", + value > 0 ? HIGHLIGHT : "", + print_value(pretty, sizeof(pretty), value, SK_SMART_ATTRIBUTE_UNIT_SECTORS), + value > 0 ? ENDHIGHLIGHT : ""); if (sk_disk_smart_get_power_on(d, &value) < 0) printf("Powered On: %s\n", strerror(errno)); @@ -1704,6 +1762,14 @@ int sk_disk_dump(SkDisk *d) { else printf("Temperature: %s\n", print_value(pretty, sizeof(pretty), value, SK_SMART_ATTRIBUTE_UNIT_MKELVIN)); + if ((ret = sk_disk_smart_get_overall(d, &overall)) < 0) + return ret; + + printf("%sOverall Status: %s%s\n", + overall != SK_SMART_OVERALL_GOOD ? HIGHLIGHT : "", + sk_smart_overall_to_string(overall), + overall != SK_SMART_OVERALL_GOOD ? ENDHIGHLIGHT : ""); + printf("%3s %-27s %5s %5s %5s %-11s %-14s %-7s %-7s %-3s\n", "ID#", "Name", diff --git a/atasmart.h b/atasmart.h index 4d4073b..096af93 100644 --- a/atasmart.h +++ b/atasmart.h @@ -25,6 +25,10 @@ #include +/* Please note that all enums defined here may be extended at any time + * without this being considered an ABI change. So take care when + * using them as indexes! */ + #ifdef __cplusplus extern "C" { #endif @@ -149,6 +153,16 @@ typedef struct SkSmartAttributeParsedData { typedef struct SkDisk SkDisk; +typedef enum SkSmartOverall { + SK_SMART_OVERALL_GOOD, + SK_SMART_OVERALL_BAD_STATUS, /* Smart Self Assessment negative */ + SK_SMART_OVERALL_BAD_SECTOR, /* At least one bad sector */ + SK_SMART_OVERALL_BAD_ATTRIBUTE, /* At least one attribute exceeded its threshold */ + _SK_SMART_OVERALL_MAX +} SkSmartOverall; + +const char* sk_smart_overall_to_string(SkSmartOverall overall); + int sk_disk_open(const char *name, SkDisk **d); int sk_disk_get_size(SkDisk *d, uint64_t *bytes); @@ -162,6 +176,7 @@ typedef void (*SkSmartAttributeParseCallback)(SkDisk *d, const SkSmartAttributeP int sk_disk_smart_is_available(SkDisk *d, SkBool *available); int sk_disk_smart_status(SkDisk *d, SkBool *good); + /* Reading SMART data might cause the disk to wake up from * sleep. Hence from monitoring daemons make sure to call * sk_disk_check_power_mode() to check wether the disk is sleeping and @@ -180,6 +195,9 @@ int sk_disk_smart_get_bad(SkDisk *d, uint64_t *sectors); /* High level API to get the temperature */ int sk_disk_smart_get_temperature(SkDisk *d, uint64_t *kelvin); +/* Get overall status. This integrates the values of a couple of fields into a single overall status */ +int sk_disk_smart_get_overall(SkDisk *d, SkSmartOverall *overall); + int sk_disk_dump(SkDisk *d); void sk_disk_free(SkDisk *d); -- cgit