From efea44b9836c88b589224a05cc588bd18b97c990 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Sun, 4 May 2008 11:42:48 -0400 Subject: [PATCH] store historical SMART data and add DriveSmartGetHistoricalData() This add sqlite3 as a dependency. --- configure.in | 4 + doc/TODO | 4 + src/Makefile.am | 3 + src/devkit-disks-daemon.c | 14 + src/devkit-disks-daemon.h | 10 +- src/devkit-disks-device-private.h | 19 + src/devkit-disks-device.c | 16 +- src/devkit-disks-device.h | 5 + src/devkit-disks-logger.c | 485 +++++++++++++++++++++++++ src/devkit-disks-logger.h | 55 +++ src/org.freedesktop.DeviceKit.Disks.Device.xml | 89 ++++- 11 files changed, 689 insertions(+), 15 deletions(-) create mode 100644 src/devkit-disks-logger.c create mode 100644 src/devkit-disks-logger.h diff --git a/configure.in b/configure.in index a493c9e..d096bda 100644 --- a/configure.in +++ b/configure.in @@ -125,6 +125,10 @@ PKG_CHECK_MODULES(LIBPARTED, [libparted >= 1.8.8]) AC_SUBST(LIBPARTED_CFLAGS) AC_SUBST(LIBPARTED_LIBS) +PKG_CHECK_MODULES(SQLITE3, [sqlite3]) +AC_SUBST(SQLITE3_CFLAGS) +AC_SUBST(SQLITE3_LIBS) + if test "x$GCC" = "xyes"; then LDFLAGS="-Wl,--as-needed $LDFLAGS" fi diff --git a/doc/TODO b/doc/TODO index 65056e6..8d8006a 100644 --- a/doc/TODO +++ b/doc/TODO @@ -2,3 +2,7 @@ - Need a way to stop polling for SMART data to avoid breaking boxes with thousands of disks - maybe default to polling if there's less than 20 drives + - Probably needs config file + +- Delete all SMART data older than N days + - Probably needs config file diff --git a/src/Makefile.am b/src/Makefile.am index d9fa1b8..8aa6019 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,6 +40,7 @@ dbusif_DATA = org.freedesktop.DeviceKit.Disks.xml org.freedesktop.DeviceKit.Disk devkit_disks_daemon_SOURCES = \ devkit-disks-daemon.h devkit-disks-daemon.c \ + devkit-disks-logger.h devkit-disks-logger.c \ devkit-disks-device.h devkit-disks-device.c \ devkit-disks-device-private.h \ mounts-file.h mounts-file.c \ @@ -49,11 +50,13 @@ devkit_disks_daemon_SOURCES = \ devkit_disks_daemon_CPPFLAGS = \ -I$(top_srcdir)/src \ -DG_LOG_DOMAIN=\"devkit-disks-daemon\" \ + $(SQLITE3_CFLAGS) \ $(DISABLE_DEPRECATED) \ $(AM_CPPFLAGS) devkit_disks_daemon_LDADD = \ $(GIO_LIBS) \ + $(SQLITE3_LIBS) \ $(DBUS_GLIB_LIBS) \ $(POLKIT_DBUS_LIBS) \ $(DEVKIT_LIBS) diff --git a/src/devkit-disks-daemon.c b/src/devkit-disks-daemon.c index f92fb37..03e89ea 100644 --- a/src/devkit-disks-daemon.c +++ b/src/devkit-disks-daemon.c @@ -89,6 +89,8 @@ struct DevkitDisksDaemonPrivate GUnixMountMonitor *mount_monitor; guint smart_refresh_timer_id; + + DevkitDisksLogger *logger; }; static void devkit_disks_daemon_class_init (DevkitDisksDaemonClass *klass); @@ -355,6 +357,10 @@ devkit_disks_daemon_finalize (GObject *object) g_source_remove (daemon->priv->smart_refresh_timer_id); } + if (daemon->priv->logger != NULL) { + g_object_unref (daemon->priv->logger); + } + G_OBJECT_CLASS (devkit_disks_daemon_parent_class)->finalize (object); } @@ -767,6 +773,8 @@ register_disks_daemon (DevkitDisksDaemon *daemon) //g_unix_mount_monitor_set_rate_limit (daemon->priv->mount_monitor, 50); g_signal_connect (daemon->priv->mount_monitor, "mounts-changed", (GCallback) mounts_changed, daemon); + daemon->priv->logger = devkit_disks_logger_new (); + return TRUE; error: return FALSE; @@ -819,6 +827,12 @@ devkit_disks_daemon_new (void) return daemon; } +DevkitDisksLogger * +devkit_disks_daemon_local_get_logger (DevkitDisksDaemon *daemon) +{ + return daemon->priv->logger; +} + PolKitCaller * devkit_disks_damon_local_get_caller_for_context (DevkitDisksDaemon *daemon, DBusGMethodInvocation *context) diff --git a/src/devkit-disks-daemon.h b/src/devkit-disks-daemon.h index 7fd77cd..1a32519 100644 --- a/src/devkit-disks-daemon.h +++ b/src/devkit-disks-daemon.h @@ -25,6 +25,11 @@ #include #include +struct DevkitDisksDevice; +typedef struct DevkitDisksDevice DevkitDisksDevice; + +#include "devkit-disks-logger.h" + G_BEGIN_DECLS #define DEVKIT_TYPE_DISKS_DAEMON (devkit_disks_daemon_get_type ()) @@ -66,9 +71,6 @@ DevkitDisksDaemon *devkit_disks_daemon_new (void); /* local methods */ -struct DevkitDisksDevice; -typedef struct DevkitDisksDevice DevkitDisksDevice; - GList *devkit_disks_daemon_local_get_all_devices (DevkitDisksDaemon *daemon); DevkitDisksDevice *devkit_disks_daemon_local_find_by_native_path (DevkitDisksDaemon *daemon, const char *native_path); @@ -88,6 +90,8 @@ void devkit_disks_daemon_local_update_mount_state (DevkitDisksDae void devkit_disks_daemon_local_synthesize_changed (DevkitDisksDaemon *daemon, DevkitDevice *d); +DevkitDisksLogger *devkit_disks_daemon_local_get_logger (DevkitDisksDaemon *daemon); + /* exported methods */ gboolean devkit_disks_daemon_enumerate_devices (DevkitDisksDaemon *daemon, diff --git a/src/devkit-disks-device-private.h b/src/devkit-disks-device-private.h index cafba43..e1a7cc2 100644 --- a/src/devkit-disks-device-private.h +++ b/src/devkit-disks-device-private.h @@ -31,6 +31,25 @@ G_BEGIN_DECLS struct Job; typedef struct Job Job; +#define SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \ + G_TYPE_INT, \ + G_TYPE_STRING, \ + G_TYPE_INT, \ + G_TYPE_INT, \ + G_TYPE_INT, \ + G_TYPE_INT, \ + G_TYPE_STRING, \ + G_TYPE_INVALID)) + +#define HISTORICAL_SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \ + G_TYPE_UINT64, \ + G_TYPE_DOUBLE, \ + G_TYPE_UINT64, \ + G_TYPE_STRING, \ + G_TYPE_BOOLEAN, \ + dbus_g_type_get_collection ("GPtrArray", SMART_DATA_STRUCT_TYPE), \ + G_TYPE_INVALID)) + struct DevkitDisksDevicePrivate { DBusGConnection *system_bus_connection; diff --git a/src/devkit-disks-device.c b/src/devkit-disks-device.c index b9a8204..93975ea 100644 --- a/src/devkit-disks-device.c +++ b/src/devkit-disks-device.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "devkit-disks-device.h" #include "devkit-disks-device-private.h" @@ -555,16 +556,6 @@ get_property (GObject *object, } } -#define SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \ - G_TYPE_INT, \ - G_TYPE_STRING, \ - G_TYPE_INT, \ - G_TYPE_INT, \ - G_TYPE_INT, \ - G_TYPE_INT, \ - G_TYPE_STRING, \ - G_TYPE_INVALID)) - static void devkit_disks_device_class_init (DevkitDisksDeviceClass *klass) { @@ -2494,7 +2485,7 @@ job_read_out (GIOChannel *channel, line = g_strndup (job->stdout_string->str + job->stdout_string_cursor, line_len); job->stdout_string_cursor += line_len + 1; - g_print ("helper(pid %5d): '%s'\n", job->pid, line); + //g_print ("helper(pid %5d): '%s'\n", job->pid, line); if (strlen (line) < 256) { int cur_task; @@ -5545,6 +5536,9 @@ drive_smart_refresh_data_completed_cb (DBusGMethodInvocation *context, /* emit change event since we've updated the smart data */ emit_changed (device); + devkit_disks_logger_record_smart_values (devkit_disks_daemon_local_get_logger (device->priv->daemon), + device); + if (context != NULL) dbus_g_method_return (context, passed, power_on_hours, temperature, last_self_test_result); out: diff --git a/src/devkit-disks-device.h b/src/devkit-disks-device.h index 74c747c..35a77ef 100644 --- a/src/devkit-disks-device.h +++ b/src/devkit-disks-device.h @@ -185,6 +185,11 @@ gboolean devkit_disks_device_drive_smart_refresh_data (DevkitDisksDevice *de char **options, DBusGMethodInvocation *context); +gboolean devkit_disks_device_drive_smart_get_historical_data (DevkitDisksDevice *device, + guint64 from, + guint64 to, + DBusGMethodInvocation *context); + gboolean devkit_disks_device_drive_smart_initiate_selftest (DevkitDisksDevice *device, const char *test, gboolean captive, diff --git a/src/devkit-disks-logger.c b/src/devkit-disks-logger.c new file mode 100644 index 0000000..148a431 --- /dev/null +++ b/src/devkit-disks-logger.c @@ -0,0 +1,485 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devkit-disks-device.h" +#include "devkit-disks-device-private.h" +#include "devkit-disks-logger.h" + +struct DevkitDisksLoggerPrivate +{ + sqlite3 *db; +}; + +static GObjectClass *parent_class = NULL; + +G_DEFINE_TYPE (DevkitDisksLogger, devkit_disks_logger, G_TYPE_OBJECT) + +#define DEVKIT_DISKS_LOGGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_TYPE_DISKS_DEVICE, DevkitDisksDevicePrivate)) + + +static void +devkit_disks_logger_finalize (DevkitDisksLogger *logger) +{ + if (logger->priv->db != NULL) + sqlite3_close (logger->priv->db); + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (logger)); +} + +static void +devkit_disks_logger_class_init (DevkitDisksLoggerClass *klass) +{ + GObjectClass *obj_class = (GObjectClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + obj_class->finalize = (GObjectFinalizeFunc) devkit_disks_logger_finalize; + +} + +static void +devkit_disks_logger_init (DevkitDisksLogger *logger) +{ + logger->priv = g_new0 (DevkitDisksLoggerPrivate, 1); +} + +DevkitDisksLogger * +devkit_disks_logger_new (void) +{ + int ret; + char *err_msg; + DevkitDisksLogger * logger; + + logger = DEVKIT_DISKS_LOGGER (g_object_new (DEVKIT_TYPE_DISKS_LOGGER, NULL)); + + ret = sqlite3_open_v2 (PACKAGE_LOCALSTATE_DIR "/lib/DeviceKit-disks/db.sqlite3", + &logger->priv->db, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, + NULL); + if (ret != SQLITE_OK) { + g_warning ("error opening db: %s", sqlite3_errmsg (logger->priv->db)); + sqlite3_close (logger->priv->db); + goto error; + } + + /* create tables */ + ret = sqlite3_exec (logger->priv->db, + "CREATE TABLE SmartEntry (" + " smart_entry_id INTEGER PRIMARY KEY, " + " disk_id TEXT, " + " time_collected INTEGER, " + " temperature INTEGER, " + " time_powered_on INTEGER, " + " last_self_test_result TEXT, " + " is_failing INTEGER" + ");" + "CREATE TABLE SmartAttr (" + " smart_entry_id INTEGER, " + " disk_id TEXT, " + " time_collected INTEGER, " + " id INTEGER, " + " name TEXT, " + " flags INTEGER, " + " value INTEGER, " + " worst INTEGER, " + " threshold INTEGER, " + " raw TEXT" + ");", + NULL, + NULL, + &err_msg); + if (ret != SQLITE_OK) { + g_warning ("SQL error: %s", err_msg); + sqlite3_free (err_msg); + } + + return logger; + +error: + g_object_unref (logger); + return NULL; +} + +static char * +drive_get_safe_uuid (DevkitDisksDevice *device) +{ + char *s; + char *result; + + result = NULL; + + if (device->priv->info.drive_vendor == NULL || strlen (device->priv->info.drive_vendor) == 0) + goto out; + if (device->priv->info.drive_model == NULL || strlen (device->priv->info.drive_model) == 0) + goto out; + if (device->priv->info.drive_revision == NULL || strlen (device->priv->info.drive_revision) == 0) + goto out; + if (device->priv->info.drive_serial == NULL || strlen (device->priv->info.drive_serial) == 0) + goto out; + + s = g_strdup_printf ("%s_%s_%s_%s", + device->priv->info.drive_vendor, + device->priv->info.drive_model, + device->priv->info.drive_revision, + device->priv->info.drive_serial); + result = g_uri_escape_string (s, NULL, FALSE); + g_free (s); + +out: + return result; +} + +void +devkit_disks_logger_record_smart_values (DevkitDisksLogger *logger, + DevkitDisksDevice *device) +{ + int n; + int ret; + char *err_msg; + char *s; + char *disk_id; + sqlite3_int64 row_id; + GString *str; + + g_return_if_fail (device != NULL); + g_return_if_fail (logger != NULL); + g_return_if_fail (logger->priv->db != NULL); + + disk_id = NULL; + + disk_id = drive_get_safe_uuid (device); + if (disk_id == NULL) { + g_warning ("no drive uuid for %s", device->priv->native_path); + goto out; + } + + s = sqlite3_mprintf ( + "BEGIN TRANSACTION;" + "INSERT INTO SmartEntry " + "(disk_id, time_collected, temperature, time_powered_on, last_self_test_result, is_failing) " + "VALUES ('%q', %" G_GUINT64_FORMAT ", %d, %" G_GUINT64_FORMAT ", '%q', %d)", + disk_id, + device->priv->drive_smart_time_collected, + (int) device->priv->drive_smart_temperature, + device->priv->drive_smart_time_powered_on, + device->priv->drive_smart_last_self_test_result, + device->priv->drive_smart_is_failing ? 1 : 0); + ret = sqlite3_exec (logger->priv->db, s, NULL, NULL, &err_msg); + sqlite3_free (s); + if (ret != SQLITE_OK) { + g_warning ("SQL error: %s", err_msg); + sqlite3_free (err_msg); + goto out; + } + + row_id = sqlite3_last_insert_rowid (logger->priv->db); + + str = g_string_new (NULL); + for (n = 0; n < (int) device->priv->drive_smart_attributes->len; n++) { + GValue elem = {0}; + int id; + char *name; + int flags; + int value; + int worst; + int threshold; + char *raw_string; + + g_value_init (&elem, SMART_DATA_STRUCT_TYPE); + g_value_set_static_boxed (&elem, device->priv->drive_smart_attributes->pdata[n]); + dbus_g_type_struct_get (&elem, + 0, &id, + 1, &name, + 2, &flags, + 3, &value, + 4, &worst, + 5, &threshold, + 6, &raw_string, + G_MAXUINT); + + s = sqlite3_mprintf ( + "INSERT INTO SmartAttr " + "VALUES (%" G_GINT64_FORMAT ", '%q', %" G_GUINT64_FORMAT ", %d, '%q', %d, %d, %d, %d, '%q');\n", + row_id, + disk_id, + device->priv->drive_smart_time_collected, + id, + name, + flags, + value, + worst, + threshold, + raw_string); + g_string_append (str, s); + sqlite3_free (s); + } + + g_string_append_printf (str, "COMMIT;"); + + s = g_string_free (str, FALSE); + ret = sqlite3_exec (logger->priv->db, s, NULL, NULL, &err_msg); + g_free (s); + if (ret != SQLITE_OK) { + g_warning ("SQL error: %s", err_msg); + sqlite3_free (err_msg); + } +out: + g_free (disk_id); +} + +static gboolean +throw_error (DBusGMethodInvocation *context, int error_code, const char *format, ...) +{ + GError *error; + va_list args; + char *message; + + if (context == NULL) + return TRUE; + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + error = g_error_new (DEVKIT_DISKS_DEVICE_ERROR, + error_code, + message); + dbus_g_method_return_error (context, error); + g_error_free (error); + g_free (message); + return TRUE; +} + +typedef struct { + GPtrArray *array; + + gint64 cur_rowid; + gboolean needs_draining; + + guint64 time_collected; + double temperature; + guint64 time_powered_on; + char last_self_test_result[256]; + gboolean is_failing; + GPtrArray *attrs; +} HistoricalData; + +static void +historical_data_drain (HistoricalData *data) +{ + GValue elem = {0}; + + if (!data->needs_draining) + return; + + g_value_init (&elem, HISTORICAL_SMART_DATA_STRUCT_TYPE); + g_value_take_boxed (&elem, dbus_g_type_specialized_construct (HISTORICAL_SMART_DATA_STRUCT_TYPE)); + dbus_g_type_struct_set (&elem, + 0, data->time_collected, + 1, data->temperature, + 2, data->time_powered_on, + 3, data->last_self_test_result, + 4, data->is_failing, + 5, data->attrs, + G_MAXUINT); + g_ptr_array_add (data->array, g_value_get_boxed (&elem)); + + g_ptr_array_foreach (data->attrs, (GFunc) g_value_array_free, NULL); + g_ptr_array_free (data->attrs, TRUE); + data->attrs = NULL; + data->needs_draining = FALSE; +} + +static int +historical_data_cb (void *user_data, int argc, char **argv, char **col_name) +{ + HistoricalData *data = (HistoricalData *) user_data; + gint64 rowid; + int id; + const char *name; + int flags; + int value; + int worst; + int threshold; + const char *raw; + + if (argc != 13) { + g_warning ("expected 13 columns, got %d instead", argc); + goto out; + } + + /* TODO: could add checks for the column types */ + + rowid = atoll (argv[0]); + if (rowid != data->cur_rowid) { + if (data->needs_draining) { + historical_data_drain (data); + } + + data->needs_draining = TRUE; + data->cur_rowid = rowid; + data->time_collected = atoll (argv[1]); + data->temperature = atof (argv[2]); + data->time_powered_on = atoll (argv[3]); + strncpy (data->last_self_test_result, argv[4], 256); + data->is_failing = (strcmp (argv[5], "0") != 0); + data->attrs = g_ptr_array_new (); + + /*g_warning ("got time_collected=%lld temperature=%g time_powered_on=%lld lstr='%s' is_failing=%d", + data->time_collected, + data->temperature, + data->time_powered_on, + data->last_self_test_result, + data->is_failing);*/ + } + + id = atoi (argv[6]); + name = argv[7]; + flags = atoi (argv[8]); + value = atoi (argv[9]); + worst = atoi (argv[10]); + threshold = atoi (argv[11]); + raw = argv[12]; + + /*g_warning ("got id=%d name='%s' flags=0x%04x value=%d worst=%d threshold=%d raw='%s'", + id, name, flags, value, worst, threshold, raw);*/ + + GValue elem = {0}; + g_value_init (&elem, SMART_DATA_STRUCT_TYPE); + g_value_take_boxed (&elem, dbus_g_type_specialized_construct (SMART_DATA_STRUCT_TYPE)); + dbus_g_type_struct_set (&elem, + 0, id, + 1, name, + 2, flags, + 3, value, + 4, worst, + 5, threshold, + 6, raw, + G_MAXUINT); + g_ptr_array_add (data->attrs, g_value_get_boxed (&elem)); + + + /* + int n; + for (n = 0; n < argc; n++) { + printf ("%s = %s\n", col_name[n], argv[n] ? argv[n] : "NULL"); + } + printf("\n"); + */ + +out: + return 0; +} + +gboolean +devkit_disks_device_drive_smart_get_historical_data (DevkitDisksDevice *device, + guint64 from, + guint64 to, + DBusGMethodInvocation *context) +{ + char *s; + char *disk_id; + GTimeVal now; + int ret; + char *err_msg; + DevkitDisksLogger *logger; + HistoricalData *data; + + logger = devkit_disks_daemon_local_get_logger (device->priv->daemon); + + disk_id = drive_get_safe_uuid (device); + if (disk_id == NULL) { + g_warning ("no drive uuid for %s", device->priv->native_path); + throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_GENERAL, "No unique disk id for device"); + goto out; + } + + if (from > to) { + throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_GENERAL, "Malformed time range (from > to)"); + goto out; + } + + if (to == 0) { + g_get_current_time (&now); + to = (guint64) now.tv_sec; + } + + data = g_new0 (HistoricalData, 1); + data->array = g_ptr_array_new (); + data->cur_rowid = -1; + + s = sqlite3_mprintf ("SELECT" + " SmartEntry.smart_entry_id," + " SmartEntry.time_collected," + " SmartEntry.temperature," + " SmartEntry.time_powered_on," + " SmartEntry.last_self_test_result," + " SmartEntry.is_failing," + " SmartAttr.id," + " SmartAttr.name," + " Smartattr.flags, " + " SmartAttr.value," + " SmartAttr.worst," + " SmartAttr.threshold," + " SmartAttr.raw " + "FROM SmartEntry, SmartAttr " + "WHERE" + " SmartEntry.disk_id='%q' AND" + " SmartEntry.smart_entry_id=SmartAttr.smart_entry_id AND" + " SmartEntry.time_collected >= %" G_GUINT64_FORMAT " AND" + " SmartEntry.time_collected <= %" G_GUINT64_FORMAT " " + "ORDER BY SmartEntry.smart_entry_id, SmartAttr.id;", + disk_id, from, to); + ret = sqlite3_exec (logger->priv->db, + s, + historical_data_cb, + data, + &err_msg); + if (ret != SQLITE_OK) { + g_warning ("SQL error: %s", err_msg); + sqlite3_free (err_msg); + } + sqlite3_free (s); + + historical_data_drain (data); + dbus_g_method_return (context, data->array); + g_ptr_array_foreach (data->array, (GFunc) g_value_array_free, NULL); + g_ptr_array_free (data->array, TRUE); + g_free (data); + +out: + g_free (disk_id); + return TRUE; +} diff --git a/src/devkit-disks-logger.h b/src/devkit-disks-logger.h new file mode 100644 index 0000000..44b1ec1 --- /dev/null +++ b/src/devkit-disks-logger.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __DEVKIT_DISKS_LOGGER_H__ +#define __DEVKIT_DISKS_LOGGER_H__ + +#include + +G_BEGIN_DECLS + +#define DEVKIT_TYPE_DISKS_LOGGER (devkit_disks_logger_get_type ()) +#define DEVKIT_DISKS_LOGGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_TYPE_DISKS_LOGGER, DevkitDisksLogger)) +#define DEVKIT_DISKS_LOGGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_TYPE_DISKS_LOGGER, DevkitDisksLoggerClass)) +#define DEVKIT_IS_DISKS_LOGGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_TYPE_DISKS_LOGGER)) +#define DEVKIT_IS_DISKS_LOGGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_TYPE_DISKS_LOGGER)) +#define DEVKIT_DISKS_LOGGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_TYPE_DISKS_LOGGER, DevkitDisksLoggerClass)) + +typedef struct DevkitDisksLoggerPrivate DevkitDisksLoggerPrivate; + +typedef struct +{ + GObject parent; + DevkitDisksLoggerPrivate *priv; +} DevkitDisksLogger; + +typedef struct +{ + GObjectClass parent_class; +} DevkitDisksLoggerClass; + +GType devkit_disks_logger_get_type (void); +DevkitDisksLogger *devkit_disks_logger_new (void); +void devkit_disks_logger_record_smart_values (DevkitDisksLogger *logger, + DevkitDisksDevice *device); + +G_END_DECLS + +#endif /* __DEVKIT_DISKS_LOGGER_H__ */ diff --git a/src/org.freedesktop.DeviceKit.Disks.Device.xml b/src/org.freedesktop.DeviceKit.Disks.Device.xml index ab08941..f961193 100644 --- a/src/org.freedesktop.DeviceKit.Disks.Device.xml +++ b/src/org.freedesktop.DeviceKit.Disks.Device.xml @@ -686,6 +686,93 @@ + + + + + Don't fetch S.M.A.R.T. data collected earlier than this point + in time (seconds since the Epoch Jan 1, 1970 0:00 UTC). + + + + + Don't fetch S.M.A.R.T. data collected later than this point in + time (seconds since the Epoch Jan 1, 1970 0:00 UTC). If 0 is + passed the current time will be used. + + + + + An array of historical S.M.A.R.T. data. Each element contains + the following members: + + + time + + When the data was collected (seconds since the Epoch Jan 1, 1970 0:00 UTC). Similar to the + drive-smart-time-collected + property. + + + + temperature + + Temperature of the drive. Similar to the + drive-smart-temperature + property. + + + + time-powered-on + + Number of the seconds the drive has been powered on. Similar to the + drive-smart-time-powered-on + property. + + + + last-self-test-result + + The result of the last self-test. Similar to the + drive-smart-last-self-test-result + property. + + + + is-failing + + If the drive is assessed to be failing. Similar to the + drive-smart-is-failing + property. + + + + attributes + + The attributes of the drive. Similar to the + drive-smart-attributes + property. + + + + + + + + + Retrieves historical S.M.A.R.T. data from the drive in the + given time interval. Note that this is data collected and + stored by the host as S.M.A.R.T. capable drives doesn't + store or return historical data. + + + + device is not S.M.A.R.T. capable + device is not a drive + if incoming parameters are invalid or an unknown error occured + + + @@ -1637,7 +1724,7 @@ - The result of the last self-test to run. The following values are known: + The result of the last self-test. The following values are known: completed_ok -- 2.7.4