summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-03-19 01:10:43 +0100
committerLennart Poettering <lennart@poettering.net>2009-03-19 01:10:43 +0100
commit2735fd3198ffc5432b6fb807c4017deb35d401de (patch)
treef5741a743c46a7fc2916c7b965aa247b365f67e8
parent70f4d5a5a95c61c64b12ac9c9ab5870bc96aec96 (diff)
add new API sk_disk_smart_get_overall()
-rw-r--r--atasmart.c94
-rw-r--r--atasmart.h18
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 = &sectors1;
- 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 = &sectors2;
- 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, &sectors) < 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 <inttypes.h>
+/* 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);