From d2f23cff093e231af63ba841d9e9a522b7f4b332 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 29 Jun 2008 17:47:46 +0200 Subject: make things a proper library --- .gitignore | 4 +- Makefile | 2 +- skdump.c | 23 ++++ smart.h | 90 ++++++++++++++ smartkit.c | 398 +++++++++++++++++++++++++++++++++++++------------------------ 5 files changed, 357 insertions(+), 160 deletions(-) create mode 100644 skdump.c create mode 100644 smart.h diff --git a/.gitignore b/.gitignore index 3e14a9a..884e119 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -smartkit -smartkit.o +skdump +*.o diff --git a/Makefile b/Makefile index 6b194a7..ab81e6b 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CFLAGS=`pkg-config --cflags glib-2.0` -pipe -Wall -W -O0 -g LIBS=`pkg-config --libs glib-2.0` -smartkit: smartkit.o +skdump: smartkit.o skdump.o $(CC) -o $@ $^ $(CFLAGS) $(LIBS) diff --git a/skdump.c b/skdump.c new file mode 100644 index 0000000..6fa9167 --- /dev/null +++ b/skdump.c @@ -0,0 +1,23 @@ +#include +#include + +#include "smart.h" + +int main(int argc, char *argv[]) { + int ret; + const char *device; + SkDevice *d; + + device = argc >= 2 ? argv[1] : "/dev/sda"; + + if ((ret = sk_disk_open(device, &d)) < 0) { + g_printerr("Failed to open disk %s: %s\n", device, strerror(errno)); + return 1; + } + + sk_disk_dump(d); + + sk_disk_free(d); + + return 0; +} diff --git a/smart.h b/smart.h new file mode 100644 index 0000000..bca06e3 --- /dev/null +++ b/smart.h @@ -0,0 +1,90 @@ +#ifndef foosmarthfoo +#define foosmarthfoo + +#include + +typedef struct SkDevice SkDevice; + +typedef struct SkIdentifyParsedData { + gchar serial[21]; + gchar firmware[9]; + gchar model[41]; +} SkIdentifyParsedData; + +typedef enum SkOfflineDataCollectionStatus { + SK_OFFLINE_DATA_COLLECTION_STATUS_NEVER, + SK_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS, + SK_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS, + SK_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED, + SK_OFFLINE_DATA_COLLECTION_STATUS_ABORTED, + SK_OFFLINE_DATA_COLLECTION_STATUS_FATAL, + SK_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN, + _SK_OFFLINE_DATA_COLLECTION_STATUS_MAX +} SkOfflineDataCollectionStatus; + +typedef struct SkSmartParsedData { + SkOfflineDataCollectionStatus offline_data_collection_status; + unsigned selftest_execution_percent_remaining; + unsigned total_offline_data_collection_seconds; + + gboolean conveyance_test_available:1; + gboolean short_and_extended_test_available:1; + gboolean start_test_available:1; + gboolean abort_test_available:1; + + unsigned short_test_polling_minutes; + unsigned extended_test_polling_minutes; + unsigned conveyance_test_polling_minutes; + + /* This structure may be extended at any time without being + * considered an ABI change. So take care when you copy it. */ +} SkSmartParsedData; + +typedef enum SkSmartAttributeUnit { + SK_SMART_ATTRIBUTE_UNIT_SECONDS, + SK_SMART_ATTRIBUTE_UNIT_SECTORS, + SK_SMART_ATTRIBUTE_UNIT_KELVIN, + _SK_SMART_ATTRIBUTE_UNIT_MAX +} SkSmartAttributeUnit; + +typedef struct SkSmartAttribute { + /* Static data */ + guint8 id; + const char *name; + guint8 threshold; + SkSmartAttributeUnit unit; /* for pretty_value */ + gboolean online:1; + gboolean prefailure:1; + + /* Volatile data */ + gboolean over_threshold:1; + guint8 value; + unsigned pretty_value; + + /* This structure may be extended at any time without being + * considered an ABI change. So take care when you copy it. */ +} SkSmartAttribute; + +typedef void (*SkSmartAttributeCallback)(SkDevice *d, const SkSmartAttribute *a, gpointer userdata); + +int sk_disk_open(const gchar *name, SkDevice **d); + +int sk_disk_check_power_mode(SkDevice *d, gboolean *mode); + +int sk_disk_identify_is_available(SkDevice *d, gboolean *b); +int sk_disk_identify_parse(SkDevice *d, const SkIdentifyParsedData **data); + +int sk_disk_smart_is_available(SkDevice *d, gboolean *b); +int sk_disk_smart_read_data(SkDevice *d); +int sk_disk_smart_parse(SkDevice *d, const SkSmartParsedData **data); +int sk_disk_smart_parse_attributes(SkDevice *d, SkSmartAttributeCallback cb, gpointer userdata); + +int sk_disk_get_size(SkDevice *d, guint64 *bytes); + +int sk_disk_dump(SkDevice *d); + +void sk_disk_free(SkDevice *d); + +const char* sk_offline_data_collection_status_to_string(SkOfflineDataCollectionStatus status); + +#endif diff --git a/smartkit.c b/smartkit.c index 2219cc0..1d981ae 100644 --- a/smartkit.c +++ b/smartkit.c @@ -11,8 +11,11 @@ #include #include #include +#include #include +#include "smart.h" + #define SK_TIMEOUT 2000 typedef enum SkDirection { @@ -23,20 +26,31 @@ typedef enum SkDirection { } SkDirection; typedef enum SkDeviceType { + SK_DEVICE_TYPE_ATA_PASSTHROUGH, /* ATA passthrough over SCSI transport */ SK_DEVICE_TYPE_ATA, SK_DEVICE_TYPE_SCSI, - SK_DEVICE_TYPE_ATA_PASSTHROUGH, /* ATA passthrough over SCSI transport */ + SK_DEVICE_TYPE_UNKNOWN, _SK_DEVICE_TYPE_MAX } SkDeviceType; -typedef struct SkDevice { +struct SkDevice { gchar *name; int fd; SkDeviceType type; + + guint64 size; + guint8 identify[512]; guint8 smart_data[512]; - gboolean smart_data_valid; -} SkDevice; + guint8 smart_threshold_data[512]; + + gboolean identify_data_valid:1; + gboolean smart_data_valid:1; + gboolean smart_threshold_data_valid:1; + + SkIdentifyParsedData identify_parsed_data; + SkSmartParsedData smart_parsed_data; +}; /* ATA commands */ typedef enum SkAtaCommand { @@ -72,6 +86,14 @@ typedef enum SkSmartTest { SK_SMART_TEST_ABORT = 127 } SkSmartTest; +static gboolean disk_smart_is_available(SkDevice *d) { + return d->identify_data_valid && !!(d->identify[164] & 1); +} + +static gboolean disk_smart_is_enabled(SkDevice *d) { + return d->identify_data_valid && !!(d->identify[170] & 1); +} + static int disk_ata_command(SkDevice *d, SkAtaCommand command, SkDirection direction, gpointer cmd_data, gpointer data, size_t *len) { guint8 *bytes = cmd_data; int ret; @@ -259,9 +281,9 @@ static int disk_passthrough_command(SkDevice *d, SkAtaCommand command, SkDirecti return ret; } -int sk_disk_command(SkDevice *d, SkAtaCommand command, SkDirection direction, gpointer cmd_data, gpointer data, size_t *len) { +static int disk_command(SkDevice *d, SkAtaCommand command, SkDirection direction, gpointer cmd_data, gpointer data, size_t *len) { - static int (* const disk_command[_SK_DEVICE_TYPE_MAX]) (SkDevice *d, SkAtaCommand command, SkDirection direction, gpointer cmd_data, gpointer data, size_t *len) = { + static int (* const disk_command_table[_SK_DEVICE_TYPE_MAX]) (SkDevice *d, SkAtaCommand command, SkDirection direction, gpointer cmd_data, gpointer data, size_t *len) = { [SK_DEVICE_TYPE_ATA] = disk_ata_command, [SK_DEVICE_TYPE_SCSI] = disk_scsi_command, [SK_DEVICE_TYPE_ATA_PASSTHROUGH] = disk_passthrough_command, @@ -274,10 +296,10 @@ int sk_disk_command(SkDevice *d, SkAtaCommand command, SkDirection direction, gp g_assert(direction == SK_DIRECTION_NONE || (data && len && *len > 0)); g_assert(direction != SK_DIRECTION_NONE || (!data && !len)); - return disk_command[d->type](d, command, direction, cmd_data, data, len); + return disk_command_table[d->type](d, command, direction, cmd_data, data, len); } -int sk_disk_identify_device(SkDevice *d) { +static int disk_identify_device(SkDevice *d) { guint16 cmd[6]; int ret; size_t len = 512; @@ -286,7 +308,7 @@ int sk_disk_identify_device(SkDevice *d) { cmd[1] = GUINT16_TO_BE(1); - if ((ret = sk_disk_command(d, SK_ATA_COMMAND_IDENTIFY_DEVICE, SK_DIRECTION_IN, cmd, d->identify, &len)) < 0) + if ((ret = disk_command(d, SK_ATA_COMMAND_IDENTIFY_DEVICE, SK_DIRECTION_IN, cmd, d->identify, &len)) < 0) return ret; if (len != 512) { @@ -294,6 +316,8 @@ int sk_disk_identify_device(SkDevice *d) { return -1; } + d->identify_data_valid = TRUE; + return 0; } @@ -301,9 +325,14 @@ int sk_disk_check_power_mode(SkDevice *d, gboolean *mode) { int ret; guint16 cmd[6]; + if (!d->identify_data_valid) { + errno = ENOTSUP; + return -1; + } + memset(cmd, 0, sizeof(cmd)); - if ((ret = sk_disk_command(d, SK_ATA_COMMAND_CHECK_POWER_MODE, SK_DIRECTION_NONE, cmd, NULL, 0)) < 0) + if ((ret = disk_command(d, SK_ATA_COMMAND_CHECK_POWER_MODE, SK_DIRECTION_NONE, cmd, NULL, 0)) < 0) return ret; if (cmd[0] != 0 || (GUINT16_FROM_BE(cmd[5]) & 1) != 0) { @@ -316,9 +345,14 @@ int sk_disk_check_power_mode(SkDevice *d, gboolean *mode) { return 0; } -int sk_disk_smart_enable(SkDevice *d, gboolean b) { +static int disk_smart_enable(SkDevice *d, gboolean b) { guint16 cmd[6]; + if (!disk_smart_is_available(d)) { + errno = ENOTSUP; + return -1; + } + memset(cmd, 0, sizeof(cmd)); cmd[0] = GUINT16_TO_BE(b ? SK_SMART_COMMAND_ENABLE_OPERATIONS : SK_SMART_COMMAND_DISABLE_OPERATIONS); @@ -326,7 +360,7 @@ int sk_disk_smart_enable(SkDevice *d, gboolean b) { cmd[3] = GUINT16_TO_BE(0x00C2U); cmd[4] = GUINT16_TO_BE(0x4F00U); - return sk_disk_command(d, SK_ATA_COMMAND_SMART, SK_DIRECTION_NONE, cmd, NULL, 0); + return disk_command(d, SK_ATA_COMMAND_SMART, SK_DIRECTION_NONE, cmd, NULL, 0); } int sk_disk_smart_read_data(SkDevice *d) { @@ -334,6 +368,11 @@ int sk_disk_smart_read_data(SkDevice *d) { int ret; size_t len = 512; + if (!disk_smart_is_available(d)) { + errno = ENOTSUP; + return -1; + } + memset(cmd, 0, sizeof(cmd)); cmd[0] = GUINT16_TO_BE(SK_SMART_COMMAND_READ_DATA); @@ -342,7 +381,7 @@ int sk_disk_smart_read_data(SkDevice *d) { cmd[3] = GUINT16_TO_BE(0x00C2U); cmd[4] = GUINT16_TO_BE(0x4F00U); - if ((ret = sk_disk_command(d, SK_ATA_COMMAND_SMART, SK_DIRECTION_IN, cmd, d->smart_data, &len)) < 0) + if ((ret = disk_command(d, SK_ATA_COMMAND_SMART, SK_DIRECTION_IN, cmd, d->smart_data, &len)) < 0) return ret; d->smart_data_valid = TRUE; @@ -378,8 +417,6 @@ int sk_disk_smart_read_data(SkDevice *d) { /* return disk_ata_command(SK_ATA_SMART, cmd, sizeof(cmd), NULL, 0); */ /* } */ -void sk_disk_free(SkDevice *d); - static void swap_strings(gchar *s, size_t len) { g_assert((len & 1) == 0); @@ -431,145 +468,231 @@ static void read_string(gchar *d, guint8 *s, size_t len) { drop_spaces(d); } -static void parse_identify(guint8 identify[512], gchar serial[21], gchar firmware[9], gchar model[41]) { - read_string(serial, identify+20, 20); - read_string(firmware, identify+46, 8); - read_string(model, identify+54, 40); +int sk_disk_identify_parse(SkDevice *d, const SkIdentifyParsedData **ipd) { + + if (!d->identify_data_valid) { + errno = ENOENT; + return -1; + } + + read_string(d->identify_parsed_data.serial, d->identify+20, 20); + read_string(d->identify_parsed_data.firmware, d->identify+46, 8); + read_string(d->identify_parsed_data.model, d->identify+54, 40); + + *ipd = &d->identify_parsed_data; + + return 0; } -gboolean sk_disk_smart_is_available(SkDevice *d) { - return !!(d->identify[164] & 1); +int sk_disk_smart_is_available(SkDevice *d, gboolean *b) { + + if (!d->identify_data_valid) { + errno = ENOTSUP; + return -1; + } + + *b = disk_smart_is_available(d); + return 0; } -gboolean sk_disk_smart_is_enabled(SkDevice *d) { - return !!(d->identify[170] & 1); +int sk_disk_identify_is_available(SkDevice *d, gboolean *b) { + + *b = d->identify_data_valid; + return 0; } -typedef enum SkOfflineDataCollectionStatus { - SK_OFFLINE_NEVER, - SK_OFFLINE_SUCCESS, - SK_OFFLINE_INPROGRESS, - SK_OFFLINE_SUSPENDED, - SK_OFFLINE_ABORTED, - SK_OFFLINE_FATAL, - SK_OFFLINE_UNKNOWN -} SkOfflineDataCollectionStatus; - -const char* const offline_data_collection_status_map[] = { - [SK_OFFLINE_NEVER] = "Off-line data collection activity was never started.", - [SK_OFFLINE_SUCCESS] = "Off-line data collection activity was completed without error.", - [SK_OFFLINE_INPROGRESS] = "Off-line activity in progress.", - [SK_OFFLINE_SUSPENDED] = "Off-line data collection activity was suspended by an interrupting command from host.", - [SK_OFFLINE_ABORTED] = "Off-line data collection activity was aborted by an interrupting command from host.", - [SK_OFFLINE_FATAL] = "Off-line data collection activity was aborted by the device with a fatal error.", - [SK_OFFLINE_UNKNOWN] = "Unknown status" -}; +const char *sk_offline_data_collection_status_to_string(SkOfflineDataCollectionStatus status) { + + static const char* const map[] = { + [SK_OFFLINE_DATA_COLLECTION_STATUS_NEVER] = "Off-line data collection activity was never started.", + [SK_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS] = "Off-line data collection activity was completed without error.", + [SK_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS] = "Off-line activity in progress.", + [SK_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED] = "Off-line data collection activity was suspended by an interrupting command from host.", + [SK_OFFLINE_DATA_COLLECTION_STATUS_ABORTED] = "Off-line data collection activity was aborted by an interrupting command from host.", + [SK_OFFLINE_DATA_COLLECTION_STATUS_FATAL] = "Off-line data collection activity was aborted by the device with a fatal error.", + [SK_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN] = "Unknown status" + }; + + if (status >= _SK_OFFLINE_DATA_COLLECTION_STATUS_MAX) + return NULL; -typedef struct SkParsedSmartData { - SkOfflineDataCollectionStatus offline_data_collection_status; - unsigned selftest_execution_percent_remaining; - unsigned total_offline_data_collection_seconds; + return map[status]; +} - gboolean conveyance_test_available:1; - gboolean short_and_extended_test_available:1; - gboolean start_test_available:1; - gboolean abort_test_available:1; - unsigned short_test_polling_minutes; - unsigned extended_test_polling_minutes; - unsigned conveyance_test_polling_minutes; -} SkParsedSmartData; +static const char *lookup_attribute_name(SkDevice *d, guint8 id) { + return "blah"; +} -void sk_disk_smart_parse(SkDevice *d, SkParsedSmartData *data) { - g_assert(d->smart_data_valid); +int sk_disk_smart_parse(SkDevice *d, const SkSmartParsedData **spd) { + + if (!d->smart_data_valid) { + errno = ENOENT; + return -1; + } switch (d->smart_data[362]) { case 0x00: case 0x80: - data->offline_data_collection_status = SK_OFFLINE_NEVER; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_NEVER; break; case 0x02: case 0x82: - data->offline_data_collection_status = SK_OFFLINE_SUCCESS; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS; break; case 0x03: - data->offline_data_collection_status = SK_OFFLINE_INPROGRESS; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS; break; case 0x04: case 0x84: - data->offline_data_collection_status = SK_OFFLINE_SUSPENDED; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED; break; case 0x05: case 0x85: - data->offline_data_collection_status = SK_OFFLINE_ABORTED; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_ABORTED; break; case 0x06: case 0x86: - data->offline_data_collection_status = SK_OFFLINE_FATAL; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_FATAL; break; default: - data->offline_data_collection_status = SK_OFFLINE_UNKNOWN; + d->smart_parsed_data.offline_data_collection_status = SK_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN; break; } - data->selftest_execution_percent_remaining = d->smart_data[363] & 0xF; + d->smart_parsed_data.selftest_execution_percent_remaining = 10*(d->smart_data[363] & 0xF); + + d->smart_parsed_data.total_offline_data_collection_seconds = (guint16) d->smart_data[364] | ((guint16) d->smart_data[365] << 8); + + d->smart_parsed_data.conveyance_test_available = !!(d->smart_data[367] & 32); + d->smart_parsed_data.short_and_extended_test_available = !!(d->smart_data[367] & 16); + d->smart_parsed_data.start_test_available = !!(d->smart_data[367] & 1); + d->smart_parsed_data.abort_test_available = !!(d->smart_data[367] & 41); + + d->smart_parsed_data.short_test_polling_minutes = d->smart_data[372]; + d->smart_parsed_data.extended_test_polling_minutes = d->smart_data[373] != 0xFF ? d->smart_data[373] : ((guint16) d->smart_data[376] << 8 | (guint16) d->smart_data[375]); + d->smart_parsed_data.conveyance_test_polling_minutes = d->smart_data[374]; + + *spd = &d->smart_parsed_data; + + return 0; +} + +int sk_disk_smart_parse_attributes(SkDevice *d, SkSmartAttributeCallback cb, gpointer userdata) { + guint8 *p; + unsigned n = 0; + + if (!d->smart_data_valid) { + errno = ENOENT; + return -1; + } + + for (n = 0, p = d->smart_data + 2; n < 30; n++, p+=12) { + SkSmartAttribute a; + + if (p[0] == 0) + continue; - data->total_offline_data_collection_seconds = (guint16) d->smart_data[364] | ((guint16) d->smart_data[365] << 8); + g_printerr("attr(%i)\t = %i\t (0x02%x)\n", p[0], p[3], p[3]); - data->conveyance_test_available = !!(d->smart_data[367] & 32); - data->short_and_extended_test_available = !!(d->smart_data[367] & 16); - data->start_test_available = !!(d->smart_data[367] & 1); - data->abort_test_available = !!(d->smart_data[367] & 41); + a.id = p[0]; + a.name = lookup_attribute_name(d, p[0]); + a.value = p[3]; + + if (cb) + cb(d, &a, userdata); + } - data->short_test_polling_minutes = d->smart_data[372]; - data->extended_test_polling_minutes = d->smart_data[373] != 0xFF ? d->smart_data[373] : ((guint16) d->smart_data[376] << 8 | (guint16) d->smart_data[375]); - data->conveyance_test_polling_minutes = d->smart_data[374]; + return 0; } static const char *yes_no(gboolean b) { return b ? "yes" : "no"; } -static void smart_dump(SkParsedSmartData *d) { - g_printerr("Off-line Collection Status: %s\n" - "Percent Self-Test Remaining: %u%%\n" - "Total Time To Complete Off-Line Data Collection: %u s\n" - "Conveyance Self-Test Available: %s\n" - "Short/Extended Self-Test Available: %s\n" - "Start Self-Test Available: %s\n" - "Abort Self-Test Available: %s\n", - offline_data_collection_status_map[d->offline_data_collection_status], - d->selftest_execution_percent_remaining, - d->total_offline_data_collection_seconds, - yes_no(d->conveyance_test_available), - yes_no(d->short_and_extended_test_available), - yes_no(d->start_test_available), - yes_no(d->abort_test_available)); - - if (d->short_and_extended_test_available) - g_printerr("Short Self-Test Polling Time: %u min\n" - "Extended Self-Test Polling Time: %u min\n", - d->short_test_polling_minutes, - d->extended_test_polling_minutes); - - if (d->conveyance_test_available) - g_printerr("Conveyance Self-Test Polling Time: %u min\n", - d->conveyance_test_polling_minutes); +int sk_disk_dump(SkDevice *d) { + int ret; + gboolean powered = FALSE; + + g_print("Device: %s\n" + "Size: %lu MiB\n", + d->name, + (unsigned long) (d->size/1024/1024)); + + if (d->identify_data_valid) { + const SkIdentifyParsedData *ipd; + + if ((ret = sk_disk_identify_parse(d, &ipd)) < 0) + return ret; + + g_print("Model: [%s]\n" + "Serial: [%s]\n" + "Firmware: [%s]\n" + "SMART Available: %s\n", + ipd->model, + ipd->serial, + ipd->firmware, + yes_no(disk_smart_is_available(d))); + } + + ret = sk_disk_check_power_mode(d, &powered); + g_print("Spin-up: %s\n", + ret >= 0 ? yes_no(powered) : "unknown"); + + if (disk_smart_is_available(d)) { + const SkSmartParsedData *spd; + + if ((ret = sk_disk_smart_read_data(d)) < 0) + return ret; + + if ((ret = sk_disk_smart_parse(d, &spd)) < 0) + return ret; + + g_print("Off-line Collection Status: %s\n" + "Percent Self-Test Remaining: %u%%\n" + "Total Time To Complete Off-Line Data Collection: %u s\n" + "Conveyance Self-Test Available: %s\n" + "Short/Extended Self-Test Available: %s\n" + "Start Self-Test Available: %s\n" + "Abort Self-Test Available: %s\n", + sk_offline_data_collection_status_to_string(spd->offline_data_collection_status), + spd->selftest_execution_percent_remaining, + spd->total_offline_data_collection_seconds, + yes_no(spd->conveyance_test_available), + yes_no(spd->short_and_extended_test_available), + yes_no(spd->start_test_available), + yes_no(spd->abort_test_available)); + + if (spd->short_and_extended_test_available) + g_print("Short Self-Test Polling Time: %u min\n" + "Extended Self-Test Polling Time: %u min\n", + spd->short_test_polling_minutes, + spd->extended_test_polling_minutes); + + if (spd->conveyance_test_available) + g_print("Conveyance Self-Test Polling Time: %u min\n", + spd->conveyance_test_polling_minutes); + + } + + return 0; +} + +int sk_disk_get_size(SkDevice *d, guint64 *bytes) { + + *bytes = d->size; + return 0; } int sk_disk_open(const gchar *name, SkDevice **_d) { SkDevice *d; - gboolean powered = FALSE; - - gchar serial[21]; - gchar firmware[9]; - gchar model[41]; + int ret = -1; g_assert(name); g_assert(_d); @@ -577,55 +700,29 @@ int sk_disk_open(const gchar *name, SkDevice **_d) { d = g_new0(SkDevice, 1); d->name = g_strdup(name); - if ((d->fd = open(name, O_RDWR|O_NOCTTY)) < 0) + if ((d->fd = open(name, O_RDWR|O_NOCTTY)) < 0) { + ret = d->fd; goto fail; - - d->type = SK_DEVICE_TYPE_ATA_PASSTHROUGH; - if (sk_disk_identify_device(d) < 0) { - - d->type = SK_DEVICE_TYPE_ATA; - if (sk_disk_identify_device(d) < 0) { - - d->type = SK_DEVICE_TYPE_SCSI; - if (sk_disk_identify_device(d) < 0) - goto fail; - } } - parse_identify(d->identify, serial, firmware, model); - - g_printerr("Serial: [%s]\n", serial); - g_printerr("Firmware: [%s]\n", firmware); - g_printerr("Model: [%s]\n", model); - - g_printerr("SMART Available: %i\n", sk_disk_smart_is_available(d)); - g_printerr("SMART Enabled: %i\n", sk_disk_smart_is_enabled(d)); + if ((ret = ioctl(d->fd, BLKGETSIZE64, &d->size)) < 0) + goto fail; - /* Check if driver can do SMART */ - if (!sk_disk_smart_is_available(d)) { - errno = ENOTSUP; + if (d->size <= 0 || d->size == (guint64) -1) { + errno = EINVAL; goto fail; } - /* Enable SMART */ - if (!sk_disk_smart_is_enabled(d)) { - if (sk_disk_smart_enable(d, TRUE) < 0) - goto fail; - g_printerr("SMART sucessfully enabled.\n"); - } + /* Find a way to identify the device */ + for (d->type = 0; d->type != SK_DEVICE_TYPE_UNKNOWN; d->type++) + if (disk_identify_device(d) >= 0) + break; - if (sk_disk_check_power_mode(d, &powered) < 0) - g_printerr("Failed to check power mode: %s", strerror(errno)); - else - g_printerr("Powered up: %i\n", (int) powered); - - if (sk_disk_smart_read_data(d) < 0) - g_printerr("Failed to read SMART data: %s", strerror(errno)); - else { - SkParsedSmartData parsed_smart_data; - sk_disk_smart_parse(d, &parsed_smart_data); - smart_dump(&parsed_smart_data); - } + /* Check if driver can do SMART, and enable if necessary */ + if (disk_smart_is_available(d)) + if (!disk_smart_is_enabled(d)) + if ((ret = disk_smart_enable(d, TRUE)) < 0) + goto fail; *_d = d; @@ -636,7 +733,7 @@ fail: if (d) sk_disk_free(d); - return -1; + return ret; } void sk_disk_free(SkDevice *d) { @@ -648,16 +745,3 @@ void sk_disk_free(SkDevice *d) { g_free(d->name); g_free(d); } - -int main(int argc, char *argv[]) { - int ret; - SkDevice *d; - - if ((ret = sk_disk_open(argc >= 2 ? argv[1] : "/dev/sda", &d)) < 0) { - g_printerr("Failed to open disk %s: %s\n", argv[1], strerror(errno)); - return 1; - } - - sk_disk_free(d); - return 0; -} -- cgit