AC_SUBST(DEVMAPPER_CFLAGS)
AC_SUBST(DEVMAPPER_LIBS)
-PKG_CHECK_MODULES(SQLITE3, [sqlite3])
-AC_SUBST(SQLITE3_CFLAGS)
-AC_SUBST(SQLITE3_LIBS)
+PKG_CHECK_MODULES(LIBATASMART, [libatasmart >= 0.2])
+AC_SUBST(LIBATASMART_CFLAGS)
+AC_SUBST(LIBATASMART_LIBS)
if test "x$GCC" = "xyes"; then
LDFLAGS="-Wl,--as-needed $LDFLAGS"
</defaults>
</action>
- <action id="org.freedesktop.devicekit.disks.drive-smart-refresh">
- <_description>Refresh S.M.A.R.T. data</_description>
- <_message>Authentication is required to refresh S.M.A.R.T. data</_message>
+ <action id="org.freedesktop.devicekit.disks.drive-ata-smart-refresh">
+ <_description>Refresh ATA SMART data</_description>
+ <_message>Authentication is required to refresh ATA SMART data</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
</defaults>
</action>
- <action id="org.freedesktop.devicekit.disks.drive-smart-selftest">
- <_description>Run S.M.A.R.T. Self Tests</_description>
- <_message>Authentication is required to run S.M.A.R.T. self tests</_message>
+ <action id="org.freedesktop.devicekit.disks.drive-ata-smart-selftest">
+ <_description>Run ATA SMART Self Tests</_description>
+ <_message>Authentication is required to run ATA SMART self tests</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
</defaults>
</action>
- <action id="org.freedesktop.devicekit.disks.drive-smart-retrieve-historical-data">
- <_description>Retrieve historical S.M.A.R.T. data</_description>
- <_message>Authentication is required to retrieve historical S.M.A.R.T. data</_message>
+ <action id="org.freedesktop.devicekit.disks.drive-ata-smart-retrieve-historical-data">
+ <_description>Retrieve historical ATA SMART data</_description>
+ <_message>Authentication is required to retrieve historical ATA SMART data</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
##############################################################################################################
# pick up data from MD components; this really should be done by rules
-* installed by mdadm or the kernel package
+# installed by mdadm or the kernel package
#
ENV{ID_FS_TYPE}=="linux_raid_member", IMPORT{program}="/sbin/mdadm --examine --export $tempnode"
##############################################################################################################
+# Check if disk is capable of ATA smart; this should probably be done by
+# ata_id and usb_id
+#
+
+ID_BUS="usb", DEVTYPE="disk", IMPORT{program}="devkit-disks-probe-ata-smart $tempnode"
+ID_BUS="scsi", ID_VENDOR="ATA", DEVTYPE="disk", IMPORT{program}="devkit-disks-probe-ata-smart $tempnode"
+
+##############################################################################################################
+
# Example rule for tagging a device with a specific media type. Where and
# how to store this database needs some thought.
#
## Process this file with automake to produce Makefile.in
+NULL =
+
INCLUDES = \
-I$(top_builddir)/src -I$(top_srcdir)/src \
-DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \
devkit-disks-types.h \
devkit-disks-private.h \
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 devkit-disks-device-private.c \
devkit-disks-mount-file.h devkit-disks-mount-file.c \
devkit-disks-helper-modify-partition \
devkit-disks-helper-create-partition-table \
devkit-disks-helper-change-filesystem-label \
- devkit-disks-helper-smart-selftest \
devkit-disks-helper-linux-md-remove-component \
- devkit-disks-helper-fstab-mounter
+ devkit-disks-helper-fstab-mounter \
+ devkit-disks-helper-ata-smart-collect \
+ devkit-disks-helper-ata-smart-selftest \
+ $(NULL)
libexec_SCRIPTS = devkit-disks-helper-change-luks-password
devkit_disks_helper_change_filesystem_label_CPPFLAGS = $(AM_CPPFLAGS)
devkit_disks_helper_change_filesystem_label_LDADD = $(GLIB_LIBS)
-devkit_disks_helper_smart_selftest_SOURCES = job-shared.h job-smart-selftest.c
-devkit_disks_helper_smart_selftest_CPPFLAGS = $(AM_CPPFLAGS)
-devkit_disks_helper_smart_selftest_LDADD = $(GLIB_LIBS)
+devkit_disks_helper_ata_smart_selftest_SOURCES = job-shared.h job-ata-smart-selftest.c
+devkit_disks_helper_ata_smart_selftest_CPPFLAGS = $(AM_CPPFLAGS) $(LIBATASMART_CFLAGS) $(GLIB_CFLAGS)
+devkit_disks_helper_ata_smart_selftest_LDADD = $(LIBATASMART_LIBS) $(GLIB_LIBS)
+
+devkit_disks_helper_ata_smart_collect_SOURCES = job-ata-smart-collect.c
+devkit_disks_helper_ata_smart_collect_CPPFLAGS = $(AM_CPPFLAGS) $(LIBATASMART_CFLAGS) $(GLIB_CFLAGS)
+devkit_disks_helper_ata_smart_collect_LDADD = $(LIBATASMART_LIBS) $(GLIB_LIBS)
devkit_disks_helper_linux_md_remove_component_SOURCES = job-shared.h job-linux-md-remove-component.c
devkit_disks_helper_linux_md_remove_component_CPPFLAGS = $(AM_CPPFLAGS)
# TODO: move to udev
udevhelperdir = $(slashlibdir)/udev
-udevhelper_PROGRAMS = devkit-disks-part-id devkit-disks-dm-export
+udevhelper_PROGRAMS = devkit-disks-part-id devkit-disks-dm-export devkit-disks-probe-ata-smart
devkit_disks_part_id_SOURCES = part-id.c
devkit_disks_part_id_CPPFLAGS = $(AM_CPPFLAGS)
devkit_disks_dm_export_SOURCES = devkit-disks-dm-export.c
devkit_disks_dm_export_CPPFLAGS = $(AM_CPPFLAGS) $(DEVMAPPER_CFLAGS)
devkit_disks_dm_export_LDADD = $(DEVMAPPER_LIBS)
+
+devkit_disks_probe_ata_smart_SOURCES = devkit-disks-probe-ata-smart.c
+devkit_disks_probe_ata_smart_CPPFLAGS = $(AM_CPPFLAGS) $(LIBATASMART_CFLAGS)
+devkit_disks_probe_ata_smart_LDADD = $(LIBATASMART_LIBS)
# end move to udev
install-data-local:
-$(mkdir_p) $(DESTDIR)$(localstatedir)/lib/DeviceKit-disks
- -chmod 0755 $(DESTDIR)$(localstatedir)/lib/DeviceKit-disks
+ -chmod 0700 $(DESTDIR)$(localstatedir)/lib/DeviceKit-disks
+ -$(mkdir_p) $(DESTDIR)$(localstatedir)/lib/DeviceKit-disks/ata-smart
#include "devkit-disks-mount-monitor.h"
#include "devkit-disks-poller.h"
#include "devkit-disks-inhibitor.h"
-#include "devkit-disks-logger.h"
#include "devkit-disks-daemon-glue.h"
#include "devkit-disks-marshal.h"
DevkitDisksMountMonitor *mount_monitor;
- guint smart_refresh_timer_id;
-
- DevkitDisksLogger *logger;
+ guint ata_smart_refresh_timer_id;
GList *polling_inhibitors;
ENUM_ENTRY (DEVKIT_DISKS_ERROR_NOT_LINUX_MD, "NotLinuxMd"),
ENUM_ENTRY (DEVKIT_DISKS_ERROR_NOT_LINUX_MD_COMPONENT, "NotLinuxComponent"),
ENUM_ENTRY (DEVKIT_DISKS_ERROR_NOT_DRIVE, "NotDrive"),
- ENUM_ENTRY (DEVKIT_DISKS_ERROR_NOT_SMART_CAPABLE, "NotSmartCapable"),
ENUM_ENTRY (DEVKIT_DISKS_ERROR_NOT_SUPPORTED, "NotSupported"),
ENUM_ENTRY (DEVKIT_DISKS_ERROR_NOT_FOUND, "NotFound"),
+ ENUM_ENTRY (DEVKIT_DISKS_ERROR_ATA_SMART_NOT_AVAILABLE, "AtaSmartNotAvailable"),
+ ENUM_ENTRY (DEVKIT_DISKS_ERROR_ATA_SMART_WOULD_WAKEUP, "AtaSmartWouldWakeup"),
{ 0, 0, 0 }
};
g_object_unref (daemon->priv->devkit_client);
}
- if (daemon->priv->smart_refresh_timer_id > 0) {
- g_source_remove (daemon->priv->smart_refresh_timer_id);
- }
-
- if (daemon->priv->logger != NULL) {
- g_object_unref (daemon->priv->logger);
+ if (daemon->priv->ata_smart_refresh_timer_id > 0) {
+ g_source_remove (daemon->priv->ata_smart_refresh_timer_id);
}
for (l = daemon->priv->polling_inhibitors; l != NULL; l = l->next) {
}
static gboolean
-refresh_smart_data (DevkitDisksDaemon *daemon)
+refresh_ata_smart_data (DevkitDisksDaemon *daemon)
{
DevkitDisksDevice *device;
const char *native_path;
g_hash_table_iter_init (&iter, daemon->priv->map_native_path_to_device);
while (g_hash_table_iter_next (&iter, (gpointer *) &native_path, (gpointer *) &device)) {
- if (device->priv->drive_smart_is_capable) {
- char *options[] = {NULL};
+ if (device->priv->drive_ata_smart_is_available) {
+ char *options[] = {"nowakeup", NULL};
- g_debug ("automatically refreshing SMART data for %s", native_path);
- devkit_disks_device_drive_smart_refresh_data (device, options, NULL);
+ g_debug ("refreshing ATA SMART data for %s", native_path);
+
+ devkit_disks_device_drive_ata_smart_refresh_data (device, options, NULL);
}
}
/* update in another 30 minutes */
- daemon->priv->smart_refresh_timer_id = g_timeout_add_seconds (30 * 60,
- (GSourceFunc) refresh_smart_data,
- daemon);
+ daemon->priv->ata_smart_refresh_timer_id = g_timeout_add_seconds (30 * 60,
+ (GSourceFunc) refresh_ata_smart_data,
+ daemon);
+
return FALSE;
}
g_signal_connect (daemon->priv->mount_monitor, "mounted", (GCallback) mount_added, daemon);
g_signal_connect (daemon->priv->mount_monitor, "unmounted", (GCallback) mount_removed, daemon);
- daemon->priv->logger = devkit_disks_logger_new ();
-
return TRUE;
error:
return FALSE;
devkit_disks_mount_file_clean_stale (l);
g_list_free (l);
- /* initial refresh of SMART data */
- refresh_smart_data (daemon);
+ /* set up timer for ATA smart data refresh */
+ daemon->priv->ata_smart_refresh_timer_id = g_timeout_add_seconds (30 * 60,
+ (GSourceFunc) refresh_ata_smart_data,
+ daemon);
return daemon;
return NULL;
}
-DevkitDisksLogger *
-devkit_disks_daemon_local_get_logger (DevkitDisksDaemon *daemon)
-{
- return daemon->priv->logger;
-}
-
DevkitDisksMountMonitor *
devkit_disks_daemon_local_get_mount_monitor (DevkitDisksDaemon *daemon)
{
DEVKIT_DISKS_ERROR_NOT_LINUX_MD,
DEVKIT_DISKS_ERROR_NOT_LINUX_MD_COMPONENT,
DEVKIT_DISKS_ERROR_NOT_DRIVE,
- DEVKIT_DISKS_ERROR_NOT_SMART_CAPABLE,
DEVKIT_DISKS_ERROR_NOT_SUPPORTED,
DEVKIT_DISKS_ERROR_NOT_FOUND,
+ DEVKIT_DISKS_ERROR_ATA_SMART_NOT_AVAILABLE,
+ DEVKIT_DISKS_ERROR_ATA_SMART_WOULD_WAKEUP,
DEVKIT_DISKS_NUM_ERRORS
} DevkitDisksError;
gboolean devkit_disks_daemon_local_has_inhibitors (DevkitDisksDaemon *daemon);
-DevkitDisksLogger *devkit_disks_daemon_local_get_logger (DevkitDisksDaemon *daemon);
-
DevkitDisksMountMonitor *devkit_disks_daemon_local_get_mount_monitor (DevkitDisksDaemon *daemon);
typedef struct {
}
}
+
void
-devkit_disks_device_set_drive_smart_is_capable (DevkitDisksDevice *device, gboolean value)
+devkit_disks_device_set_drive_ata_smart_is_available (DevkitDisksDevice *device, gboolean value)
{
- if (G_UNLIKELY (device->priv->drive_smart_is_capable != value))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_is_available != value))
{
- device->priv->drive_smart_is_capable = value;
- emit_changed (device, "drive_smart_is_capable");
+ device->priv->drive_ata_smart_is_available = value;
+ emit_changed (device, "drive_ata_smart_is_available");
}
}
void
-devkit_disks_device_set_drive_smart_is_enabled (DevkitDisksDevice *device, gboolean value)
+devkit_disks_device_set_drive_ata_smart_is_failing (DevkitDisksDevice *device, gboolean value)
{
- if (G_UNLIKELY (device->priv->drive_smart_is_enabled != value))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_is_failing != value))
{
- device->priv->drive_smart_is_enabled = value;
- emit_changed (device, "drive_smart_is_enabled");
+ device->priv->drive_ata_smart_is_failing = value;
+ emit_changed (device, "drive_ata_smart_is_failing");
}
}
void
-devkit_disks_device_set_drive_smart_time_collected (DevkitDisksDevice *device, guint64 value)
+devkit_disks_device_set_drive_ata_smart_is_failing_valid (DevkitDisksDevice *device, gboolean value)
{
- if (G_UNLIKELY (device->priv->drive_smart_time_collected != value))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_is_failing_valid != value))
{
- device->priv->drive_smart_time_collected = value;
- emit_changed (device, "drive_smart_time_collected");
+ device->priv->drive_ata_smart_is_failing_valid = value;
+ emit_changed (device, "drive_ata_smart_is_failing_valid");
}
}
void
-devkit_disks_device_set_drive_smart_is_failing (DevkitDisksDevice *device, gboolean value)
+devkit_disks_device_set_drive_ata_smart_has_bad_sectors (DevkitDisksDevice *device, gboolean value)
{
- if (G_UNLIKELY (device->priv->drive_smart_is_failing != value))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_has_bad_sectors != value))
{
- device->priv->drive_smart_is_failing = value;
- emit_changed (device, "drive_smart_is_failing");
+ device->priv->drive_ata_smart_has_bad_sectors = value;
+ emit_changed (device, "drive_ata_smart_has_bad_sectors");
}
}
void
-devkit_disks_device_set_drive_smart_temperature (DevkitDisksDevice *device, gdouble value)
+devkit_disks_device_set_drive_ata_smart_has_bad_attributes (DevkitDisksDevice *device, gboolean value)
{
- if (G_UNLIKELY (device->priv->drive_smart_temperature != value))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_has_bad_attributes != value))
{
- device->priv->drive_smart_temperature = value;
- emit_changed (device, "drive_smart_temperature");
+ device->priv->drive_ata_smart_has_bad_attributes = value;
+ emit_changed (device, "drive_ata_smart_has_bad_attributes");
}
}
void
-devkit_disks_device_set_drive_smart_time_powered_on (DevkitDisksDevice *device, guint64 value)
+devkit_disks_device_set_drive_ata_smart_temperature_kelvin (DevkitDisksDevice *device, gdouble value)
{
- if (G_UNLIKELY (device->priv->drive_smart_time_powered_on != value))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_temperature_kelvin != value))
{
- device->priv->drive_smart_time_powered_on = value;
- emit_changed (device, "drive_smart_time_powered_on");
+ device->priv->drive_ata_smart_temperature_kelvin = value;
+ emit_changed (device, "drive_ata_smart_temperature_kelvin");
}
}
void
-devkit_disks_device_set_drive_smart_last_self_test_result (DevkitDisksDevice *device, const gchar *value)
+devkit_disks_device_set_drive_ata_smart_power_on_seconds (DevkitDisksDevice *device, guint64 value)
{
- if (G_UNLIKELY (g_strcmp0 (device->priv->drive_smart_last_self_test_result, value) != 0))
+ if (G_UNLIKELY (device->priv->drive_ata_smart_power_on_seconds != value))
{
- g_free (device->priv->drive_smart_last_self_test_result);
- device->priv->drive_smart_last_self_test_result = g_strdup (value);
- emit_changed (device, "drive_smart_last_self_test_result");
+ device->priv->drive_ata_smart_power_on_seconds = value;
+ emit_changed (device, "drive_ata_smart_power_on_seconds");
}
}
-/* NOTE: steals attributes! */
void
-devkit_disks_device_set_drive_smart_attributes_steal (DevkitDisksDevice *device, GPtrArray *attributes)
+devkit_disks_device_set_drive_ata_smart_time_collected (DevkitDisksDevice *device, guint64 value)
{
- /* TODO: compare? Not really needed, this happens very rarely */
+ if (G_UNLIKELY (device->priv->drive_ata_smart_time_collected != value))
+ {
+ device->priv->drive_ata_smart_time_collected = value;
+ emit_changed (device, "drive_ata_smart_time_collected");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_offline_data_collection_status (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_offline_data_collection_status != value))
+ {
+ device->priv->drive_ata_smart_offline_data_collection_status = value;
+ emit_changed (device, "drive_ata_smart_offline_data_collection_status");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_offline_data_collection_seconds (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_offline_data_collection_seconds != value))
+ {
+ device->priv->drive_ata_smart_offline_data_collection_seconds = value;
+ emit_changed (device, "drive_ata_smart_offline_data_collection_seconds");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_self_test_execution_status (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_self_test_execution_status != value))
+ {
+ device->priv->drive_ata_smart_self_test_execution_status = value;
+ emit_changed (device, "drive_ata_smart_self_test_execution_status");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_self_test_execution_percent_remaining (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_self_test_execution_percent_remaining != value))
+ {
+ device->priv->drive_ata_smart_self_test_execution_percent_remaining = value;
+ emit_changed (device, "drive_ata_smart_self_test_execution_percent_remaining");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_short_and_extended_self_test_available (DevkitDisksDevice *device, gboolean value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_short_and_extended_self_test_available != value))
+ {
+ device->priv->drive_ata_smart_short_and_extended_self_test_available = value;
+ emit_changed (device, "drive_ata_smart_short_and_extended_self_test_available");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_conveyance_self_test_available (DevkitDisksDevice *device, gboolean value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_conveyance_self_test_available != value))
+ {
+ device->priv->drive_ata_smart_conveyance_self_test_available = value;
+ emit_changed (device, "drive_ata_smart_conveyance_self_test_available");
+ }
+}
- g_ptr_array_foreach (device->priv->drive_smart_attributes, (GFunc) g_value_array_free, NULL);
- g_ptr_array_free (device->priv->drive_smart_attributes, TRUE);
+void
+devkit_disks_device_set_drive_ata_smart_start_self_test_available (DevkitDisksDevice *device, gboolean value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_start_self_test_available != value))
+ {
+ device->priv->drive_ata_smart_start_self_test_available = value;
+ emit_changed (device, "drive_ata_smart_start_self_test_available");
+ }
+}
- device->priv->drive_smart_attributes = attributes;
+void
+devkit_disks_device_set_drive_ata_smart_abort_self_test_available (DevkitDisksDevice *device, gboolean value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_abort_self_test_available != value))
+ {
+ device->priv->drive_ata_smart_abort_self_test_available = value;
+ emit_changed (device, "drive_ata_smart_abort_self_test_available");
+ }
+}
- emit_changed (device, "drive_smart_attributes");
+void
+devkit_disks_device_set_drive_ata_smart_short_self_test_polling_minutes (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_short_self_test_polling_minutes != value))
+ {
+ device->priv->drive_ata_smart_short_self_test_polling_minutes = value;
+ emit_changed (device, "drive_ata_smart_short_self_test_polling_minutes");
+ }
}
+void
+devkit_disks_device_set_drive_ata_smart_extended_self_test_polling_minutes (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_extended_self_test_polling_minutes != value))
+ {
+ device->priv->drive_ata_smart_extended_self_test_polling_minutes = value;
+ emit_changed (device, "drive_ata_smart_extended_self_test_polling_minutes");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_conveyance_self_test_polling_minutes (DevkitDisksDevice *device, guint value)
+{
+ if (G_UNLIKELY (device->priv->drive_ata_smart_conveyance_self_test_polling_minutes != value))
+ {
+ device->priv->drive_ata_smart_conveyance_self_test_polling_minutes = value;
+ emit_changed (device, "drive_ata_smart_conveyance_self_test_polling_minutes");
+ }
+}
+
+void
+devkit_disks_device_set_drive_ata_smart_attributes_steal (DevkitDisksDevice *device, GPtrArray *attributes)
+{
+ /* TODO: compare? Not really needed, this happens very rarely */
+
+ g_ptr_array_foreach (device->priv->drive_ata_smart_attributes, (GFunc) g_value_array_free, NULL);
+ g_ptr_array_free (device->priv->drive_ata_smart_attributes, TRUE);
+
+ device->priv->drive_ata_smart_attributes = attributes;
+
+ emit_changed (device, "drive_ata_smart_attributes");
+}
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))
+#define ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_UINT, \
+ G_TYPE_STRING, \
+ G_TYPE_UINT, \
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \
+ G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+ G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+ G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \
+ G_TYPE_UINT, G_TYPE_UINT64, \
+ dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR), \
+ G_TYPE_INVALID))
+
+#define ATA_SMART_HISTORICAL_SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_UINT64, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_DOUBLE, \
+ G_TYPE_UINT64, \
+ dbus_g_type_get_collection ("GPtrArray", ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE), \
+ G_TYPE_INVALID))
#define LSOF_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
G_TYPE_UINT, \
double linux_md_sync_percentage;
guint64 linux_md_sync_speed;
- /* We want S.M.A.R.T. to persist over change events */
- gboolean drive_smart_is_capable;
- gboolean drive_smart_is_enabled;
- guint64 drive_smart_time_collected;
- gboolean drive_smart_is_failing;
- double drive_smart_temperature;
- guint64 drive_smart_time_powered_on;
- char *drive_smart_last_self_test_result;
- GPtrArray *drive_smart_attributes;
+ gboolean drive_ata_smart_is_available;
+ gboolean drive_ata_smart_is_failing;
+ gboolean drive_ata_smart_is_failing_valid;
+ gboolean drive_ata_smart_has_bad_sectors;
+ gboolean drive_ata_smart_has_bad_attributes;
+ gdouble drive_ata_smart_temperature_kelvin;
+ guint64 drive_ata_smart_power_on_seconds;
+ guint64 drive_ata_smart_time_collected;
+ guint drive_ata_smart_offline_data_collection_status;
+ guint drive_ata_smart_offline_data_collection_seconds;
+ guint drive_ata_smart_self_test_execution_status;
+ guint drive_ata_smart_self_test_execution_percent_remaining;
+ gboolean drive_ata_smart_short_and_extended_self_test_available;
+ gboolean drive_ata_smart_conveyance_self_test_available;
+ gboolean drive_ata_smart_start_self_test_available;
+ gboolean drive_ata_smart_abort_self_test_available;
+ guint drive_ata_smart_short_self_test_polling_minutes;
+ guint drive_ata_smart_extended_self_test_polling_minutes;
+ guint drive_ata_smart_conveyance_self_test_polling_minutes;
+ GPtrArray *drive_ata_smart_attributes;
/* the following properties are not (yet) exported */
char *dm_name;
void devkit_disks_device_set_slaves_objpath (DevkitDisksDevice *device, GStrv value);
void devkit_disks_device_set_holders_objpath (DevkitDisksDevice *device, GStrv value);
-void devkit_disks_device_set_drive_smart_is_capable (DevkitDisksDevice *device, gboolean value);
-void devkit_disks_device_set_drive_smart_is_enabled (DevkitDisksDevice *device, gboolean value);
-void devkit_disks_device_set_drive_smart_time_collected (DevkitDisksDevice *device, guint64 value);
-void devkit_disks_device_set_drive_smart_is_failing (DevkitDisksDevice *device, gboolean value);
-void devkit_disks_device_set_drive_smart_temperature (DevkitDisksDevice *device, gdouble value);
-void devkit_disks_device_set_drive_smart_time_powered_on (DevkitDisksDevice *device, guint64 value);
-void devkit_disks_device_set_drive_smart_last_self_test_result (DevkitDisksDevice *device, const gchar *value);
-void devkit_disks_device_set_drive_smart_attributes_steal (DevkitDisksDevice *device, GPtrArray *attributes);
+void devkit_disks_device_set_drive_ata_smart_is_available (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_is_failing (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_is_failing_valid (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_has_bad_sectors (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_has_bad_attributes (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_temperature_kelvin (DevkitDisksDevice *device, gdouble value);
+void devkit_disks_device_set_drive_ata_smart_power_on_seconds (DevkitDisksDevice *device, guint64 value);
+void devkit_disks_device_set_drive_ata_smart_time_collected (DevkitDisksDevice *device, guint64 value);
+void devkit_disks_device_set_drive_ata_smart_offline_data_collection_status (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_offline_data_collection_seconds (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_self_test_execution_status (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_self_test_execution_percent_remaining (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_short_and_extended_self_test_available (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_conveyance_self_test_available (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_start_self_test_available (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_abort_self_test_available (DevkitDisksDevice *device, gboolean value);
+void devkit_disks_device_set_drive_ata_smart_short_self_test_polling_minutes (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_extended_self_test_polling_minutes (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_conveyance_self_test_polling_minutes (DevkitDisksDevice *device, guint value);
+void devkit_disks_device_set_drive_ata_smart_attributes_steal (DevkitDisksDevice *device, GPtrArray *attributes);
+
G_END_DECLS
#include <sqlite3.h>
#include "devkit-disks-daemon.h"
-#include "devkit-disks-logger.h"
#include "devkit-disks-device.h"
#include "devkit-disks-device-private.h"
#include "devkit-disks-marshal.h"
PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS,
PROP_OPTICAL_DISC_NUM_SESSIONS,
- PROP_DRIVE_SMART_IS_CAPABLE,
- PROP_DRIVE_SMART_IS_ENABLED,
- PROP_DRIVE_SMART_TIME_COLLECTED,
- PROP_DRIVE_SMART_IS_FAILING,
- PROP_DRIVE_SMART_TEMPERATURE,
- PROP_DRIVE_SMART_TIME_POWERED_ON,
- PROP_DRIVE_SMART_LAST_SELF_TEST_RESULT,
- PROP_DRIVE_SMART_ATTRIBUTES,
+ PROP_DRIVE_ATA_SMART_IS_AVAILABLE,
+ PROP_DRIVE_ATA_SMART_IS_FAILING,
+ PROP_DRIVE_ATA_SMART_IS_FAILING_VALID,
+ PROP_DRIVE_ATA_SMART_HAS_BAD_SECTORS,
+ PROP_DRIVE_ATA_SMART_HAS_BAD_ATTRIBUTES,
+ PROP_DRIVE_ATA_SMART_TEMPERATURE_KELVIN,
+ PROP_DRIVE_ATA_SMART_POWER_ON_SECONDS,
+ PROP_DRIVE_ATA_SMART_TIME_COLLECTED,
+ PROP_DRIVE_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS,
+ PROP_DRIVE_ATA_SMART_OFFLINE_DATA_COLLECTION_SECONDS,
+ PROP_DRIVE_ATA_SMART_SELF_TEST_EXECUTION_STATUS,
+ PROP_DRIVE_ATA_SMART_SELF_TEST_EXECUTION_PERCENT_REMAINING,
+ PROP_DRIVE_ATA_SMART_SHORT_AND_EXTENDED_SELF_TEST_AVAILABLE,
+ PROP_DRIVE_ATA_SMART_CONVEYANCE_SELF_TEST_AVAILABLE,
+ PROP_DRIVE_ATA_SMART_START_SELF_TEST_AVAILABLE,
+ PROP_DRIVE_ATA_SMART_ABORT_SELF_TEST_AVAILABLE,
+ PROP_DRIVE_ATA_SMART_SHORT_SELF_TEST_POLLING_MINUTES,
+ PROP_DRIVE_ATA_SMART_EXTENDED_SELF_TEST_POLLING_MINUTES,
+ PROP_DRIVE_ATA_SMART_CONVEYANCE_SELF_TEST_POLLING_MINUTES,
+ PROP_DRIVE_ATA_SMART_ATTRIBUTES,
PROP_LINUX_MD_COMPONENT_LEVEL,
PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
g_value_set_uint (value, device->priv->optical_disc_num_sessions);
break;
- case PROP_DRIVE_SMART_IS_CAPABLE:
- g_value_set_boolean (value, device->priv->drive_smart_is_capable);
+ case PROP_DRIVE_ATA_SMART_IS_AVAILABLE:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_is_available);
break;
- case PROP_DRIVE_SMART_IS_ENABLED:
- g_value_set_boolean (value, device->priv->drive_smart_is_enabled);
+ case PROP_DRIVE_ATA_SMART_IS_FAILING:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_is_failing);
break;
- case PROP_DRIVE_SMART_TIME_COLLECTED:
- g_value_set_uint64 (value, device->priv->drive_smart_time_collected);
+ case PROP_DRIVE_ATA_SMART_IS_FAILING_VALID:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_is_failing_valid);
break;
- case PROP_DRIVE_SMART_IS_FAILING:
- g_value_set_boolean (value, device->priv->drive_smart_is_failing);
+ case PROP_DRIVE_ATA_SMART_HAS_BAD_SECTORS:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_has_bad_sectors);
break;
- case PROP_DRIVE_SMART_TEMPERATURE:
- g_value_set_double (value, device->priv->drive_smart_temperature);
+ case PROP_DRIVE_ATA_SMART_HAS_BAD_ATTRIBUTES:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_has_bad_attributes);
break;
- case PROP_DRIVE_SMART_TIME_POWERED_ON:
- g_value_set_uint64 (value, device->priv->drive_smart_time_powered_on);
+ case PROP_DRIVE_ATA_SMART_TEMPERATURE_KELVIN:
+ g_value_set_double (value, device->priv->drive_ata_smart_temperature_kelvin);
break;
- case PROP_DRIVE_SMART_LAST_SELF_TEST_RESULT:
- g_value_set_string (value, device->priv->drive_smart_last_self_test_result);
+ case PROP_DRIVE_ATA_SMART_POWER_ON_SECONDS:
+ g_value_set_uint64 (value, device->priv->drive_ata_smart_power_on_seconds);
break;
- case PROP_DRIVE_SMART_ATTRIBUTES:
- g_value_set_boxed (value, device->priv->drive_smart_attributes);
+ case PROP_DRIVE_ATA_SMART_TIME_COLLECTED:
+ g_value_set_uint64 (value, device->priv->drive_ata_smart_time_collected);
+ break;
+ case PROP_DRIVE_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS:
+ g_value_set_uint (value, device->priv->drive_ata_smart_offline_data_collection_status);
+ break;
+ case PROP_DRIVE_ATA_SMART_OFFLINE_DATA_COLLECTION_SECONDS:
+ g_value_set_uint (value, device->priv->drive_ata_smart_offline_data_collection_seconds);
+ break;
+ case PROP_DRIVE_ATA_SMART_SELF_TEST_EXECUTION_STATUS:
+ g_value_set_uint (value, device->priv->drive_ata_smart_self_test_execution_status);
+ break;
+ case PROP_DRIVE_ATA_SMART_SELF_TEST_EXECUTION_PERCENT_REMAINING:
+ g_value_set_uint (value, device->priv->drive_ata_smart_self_test_execution_percent_remaining);
+ break;
+ case PROP_DRIVE_ATA_SMART_SHORT_AND_EXTENDED_SELF_TEST_AVAILABLE:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_short_and_extended_self_test_available);
+ break;
+ case PROP_DRIVE_ATA_SMART_CONVEYANCE_SELF_TEST_AVAILABLE:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_conveyance_self_test_available);
+ break;
+ case PROP_DRIVE_ATA_SMART_START_SELF_TEST_AVAILABLE:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_start_self_test_available);
+ break;
+ case PROP_DRIVE_ATA_SMART_ABORT_SELF_TEST_AVAILABLE:
+ g_value_set_boolean (value, device->priv->drive_ata_smart_abort_self_test_available);
+ break;
+ case PROP_DRIVE_ATA_SMART_SHORT_SELF_TEST_POLLING_MINUTES:
+ g_value_set_uint (value, device->priv->drive_ata_smart_short_self_test_polling_minutes);
+ break;
+ case PROP_DRIVE_ATA_SMART_EXTENDED_SELF_TEST_POLLING_MINUTES:
+ g_value_set_uint (value, device->priv->drive_ata_smart_extended_self_test_polling_minutes);
+ break;
+ case PROP_DRIVE_ATA_SMART_CONVEYANCE_SELF_TEST_POLLING_MINUTES:
+ g_value_set_uint (value, device->priv->drive_ata_smart_conveyance_self_test_polling_minutes);
+ break;
+ case PROP_DRIVE_ATA_SMART_ATTRIBUTES:
+ g_value_set_boxed (value, device->priv->drive_ata_smart_attributes);
break;
case PROP_LINUX_MD_COMPONENT_LEVEL:
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_IS_CAPABLE,
- g_param_spec_boolean ("drive-smart-is-capable", NULL, NULL, FALSE, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_IS_AVAILABLE,
+ g_param_spec_boolean ("drive-ata-smart-is-available", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_IS_FAILING,
+ g_param_spec_boolean ("drive-ata-smart-is-failing", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_IS_FAILING_VALID,
+ g_param_spec_boolean ("drive-ata-smart-is-failing-valid", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_HAS_BAD_SECTORS,
+ g_param_spec_boolean ("drive-ata-smart-has-bad-sectors", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_HAS_BAD_ATTRIBUTES,
+ g_param_spec_boolean ("drive-ata-smart-has-bad-attributes", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_TEMPERATURE_KELVIN,
+ g_param_spec_double ("drive-ata-smart-temperature-kelvin", NULL, NULL, 0, G_MAXDOUBLE, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_POWER_ON_SECONDS,
+ g_param_spec_uint64 ("drive-ata-smart-power-on-seconds", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_TIME_COLLECTED,
+ g_param_spec_uint64 ("drive-ata-smart-time-collected", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS,
+ g_param_spec_uint ("drive-ata-smart-offline-data-collection-status", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_OFFLINE_DATA_COLLECTION_SECONDS,
+ g_param_spec_uint ("drive-ata-smart-offline-data-collection-seconds", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_SELF_TEST_EXECUTION_STATUS,
+ g_param_spec_uint ("drive-ata-smart-self-test-execution-status", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_SELF_TEST_EXECUTION_PERCENT_REMAINING,
+ g_param_spec_uint ("drive-ata-smart-self-test-execution-percent-remaining", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_DRIVE_ATA_SMART_SHORT_AND_EXTENDED_SELF_TEST_AVAILABLE,
+ g_param_spec_boolean ("drive-ata-smart-short-and-extended-self-test-available", NULL, NULL, FALSE, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_IS_ENABLED,
- g_param_spec_boolean ("drive-smart-is-enabled", NULL, NULL, FALSE, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_CONVEYANCE_SELF_TEST_AVAILABLE,
+ g_param_spec_boolean ("drive-ata-smart-conveyance-self-test-available", NULL, NULL, FALSE, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_TIME_COLLECTED,
- g_param_spec_uint64 ("drive-smart-time-collected", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_START_SELF_TEST_AVAILABLE,
+ g_param_spec_boolean ("drive-ata-smart-start-self-test-available", NULL, NULL, FALSE, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_IS_FAILING,
- g_param_spec_boolean ("drive-smart-is-failing", NULL, NULL, FALSE, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_ABORT_SELF_TEST_AVAILABLE,
+ g_param_spec_boolean ("drive-ata-smart-abort-self-test-available", NULL, NULL, FALSE, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_TEMPERATURE,
- g_param_spec_double ("drive-smart-temperature", NULL, NULL, -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_SHORT_SELF_TEST_POLLING_MINUTES,
+ g_param_spec_uint ("drive-ata-smart-short-self-test-polling-minutes", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_TIME_POWERED_ON,
- g_param_spec_uint64 ("drive-smart-time-powered-on", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_EXTENDED_SELF_TEST_POLLING_MINUTES,
+ g_param_spec_uint ("drive-ata-smart-extended-self-test-polling-minutes", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_LAST_SELF_TEST_RESULT,
- g_param_spec_string ("drive-smart-last-self-test-result", NULL, NULL, NULL, G_PARAM_READABLE));
+ PROP_DRIVE_ATA_SMART_CONVEYANCE_SELF_TEST_POLLING_MINUTES,
+ g_param_spec_uint ("drive-ata-smart-conveyance-self-test-polling-minutes", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_DRIVE_SMART_ATTRIBUTES,
- g_param_spec_boxed ("drive-smart-attributes", NULL, NULL,
- dbus_g_type_get_collection ("GPtrArray", SMART_DATA_STRUCT_TYPE),
+ PROP_DRIVE_ATA_SMART_ATTRIBUTES,
+ g_param_spec_boxed ("drive-ata-smart-attributes", NULL, NULL,
+ dbus_g_type_get_collection ("GPtrArray", ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE),
G_PARAM_READABLE));
+
g_object_class_install_property (
object_class,
PROP_LINUX_MD_COMPONENT_LEVEL,
device->priv->slaves_objpath = g_ptr_array_new ();
device->priv->holders_objpath = g_ptr_array_new ();
- device->priv->drive_smart_attributes = g_ptr_array_new ();
+ device->priv->drive_ata_smart_attributes = g_ptr_array_new ();
}
static void
g_free (device->priv->native_path);
- g_free (device->priv->drive_smart_last_self_test_result);
- g_ptr_array_foreach (device->priv->drive_smart_attributes, (GFunc) g_value_array_free, NULL);
- g_ptr_array_free (device->priv->drive_smart_attributes, TRUE);
+ g_ptr_array_foreach (device->priv->drive_ata_smart_attributes, (GFunc) g_value_array_free, NULL);
+ g_ptr_array_free (device->priv->drive_ata_smart_attributes, TRUE);
for (l = device->priv->polling_inhibitors; l != NULL; l = l->next) {
DevkitDisksInhibitor *inhibitor = DEVKIT_DISKS_INHIBITOR (l->data);
/* ---------------------------------------------------------------------------------------------------- */
-/* update drive_smart_* properties */
+/* update drive_ata_smart_* properties */
static gboolean
-update_info_drive_smart (DevkitDisksDevice *device)
+update_info_drive_ata_smart (DevkitDisksDevice *device)
{
- /* Set whether device is S.M.A.R.T. capable
- *
- * TODO: need to check that it's hard disk and not e.g. an optical drive
- *
- * TODO: need to honor a quirk for certain USB drives being smart capable, cf.
- *
- * Thanks to contributor Matthieu Castet, smartctl has
- * a new option '-d usbcypress'. So you can address
- * USB devices with cypress chips. The chipset
- * contains an ATACB proprietary pass through for ATA
- * commands passed through SCSI commands. Get current
- * version from CVS.
- *
- * from http://smartmontools.sourceforge.net/
- */
+ gboolean ata_smart_is_available;
- /* drive_smart_is_capable */
- if (device->priv->drive_connection_interface != NULL && g_str_has_prefix (device->priv->drive_connection_interface, "ata")) {
- devkit_disks_device_set_drive_smart_is_capable (device, TRUE);
- } else {
- devkit_disks_device_set_drive_smart_is_capable (device, FALSE);
- }
+ ata_smart_is_available = FALSE;
+ if (device->priv->device_is_drive &&
+ devkit_device_has_property (device->priv->d, "DKD_ATA_SMART_IS_AVAILABLE"))
+ ata_smart_is_available = devkit_device_get_property_as_boolean (device->priv->d, "DKD_ATA_SMART_IS_AVAILABLE");
+
+ devkit_disks_device_set_drive_ata_smart_is_available (device, ata_smart_is_available);
+
+ /* NOTE: we don't collect ATA SMART data here, we only set whether the device is ATA SMART capable;
+ * collecting data is done in separate routines, see the
+ * devkit_disks_device_drive_ata_smart_refresh_data() function for details.
+ */
return TRUE;
}
if (!update_info_linux_md (device))
goto out;
- /* drive_smart_* properties */
- if (!update_info_drive_smart (device))
+ /* drive_ata_smart_* properties */
+ if (!update_info_drive_ata_smart (device))
goto out;
/* device_is_system_internal property */
goto out;
}
+ /* if just added, update the smart data if applicable */
+ if (device->priv->drive_ata_smart_is_available) {
+ gchar *ata_smart_refresh_data_options[] = {NULL};
+ devkit_disks_device_drive_ata_smart_refresh_data (device,
+ ata_smart_refresh_data_options,
+ NULL);
+ }
+
out:
return device;
}
/*--------------------------------------------------------------------------------------------------------------*/
+static gchar *
+get_ata_smart_filename (DevkitDisksDevice *device)
+{
+ gchar *filename;
+
+ /* TODO: hmm... unique enough? Thinking serial number collisions.. but ata_id, scsi_id, usb_id in
+ * udev should take care of that...
+ */
+ filename = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/DeviceKit-disks/ata-smart/%s-%s-%s-%s",
+ device->priv->drive_vendor,
+ device->priv->drive_model,
+ device->priv->drive_revision,
+ device->priv->drive_serial);
+
+ return filename;
+}
+
+static gboolean
+ata_smart_parse_attribute (const gchar *tokens, GValue *elem)
+{
+ gboolean ret;
+ guint id;
+ guint flags;
+ gboolean online, prefailure;
+ guint current;
+ gboolean current_valid;
+ guint worst;
+ gboolean worst_valid;
+ guint threshold;
+ gboolean threshold_valid;
+ gboolean good, good_valid;
+ guint pretty_unit;
+ guint64 pretty_value;
+ guint raw0, raw1, raw2, raw3, raw4, raw5;
+ gchar name[256];
+ GArray *raw_data;
+
+ ret = FALSE;
+
+ if (sscanf (tokens,
+ "%d " /* id */
+ "%s " /* name */
+ "%d " /* flags */
+ "%d %d " /* online, prefailure */
+ "%d %d " /* current_value, current_value_valid */
+ "%d %d " /* worst_value, worst_value_valid */
+ "%d %d " /* threshold, threshold_valid */
+ "%d %d " /* good, good_valid */
+ "%d %" G_GUINT64_FORMAT " " /* pretty_unit, pretty_value */
+ "%02x %02x %02x %02x %02x %02x", /* raw[6] */
+ &id,
+ name,
+ &flags,
+ &online, &prefailure,
+ ¤t, ¤t_valid,
+ &worst, &worst_valid,
+ &threshold, &threshold_valid,
+ &good, &good_valid,
+ &pretty_unit, &pretty_value,
+ &raw0, &raw1, &raw2, &raw3, &raw4, &raw5) != 21) {
+ goto out;
+ }
+
+ raw_data = g_array_new (FALSE, TRUE, sizeof (guchar));
+ g_array_append_val (raw_data, raw0);
+ g_array_append_val (raw_data, raw1);
+ g_array_append_val (raw_data, raw2);
+ g_array_append_val (raw_data, raw3);
+ g_array_append_val (raw_data, raw4);
+ g_array_append_val (raw_data, raw5);
+
+ g_value_init (elem, ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE);
+ g_value_take_boxed (elem, dbus_g_type_specialized_construct (ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE));
+ dbus_g_type_struct_set (elem,
+ 0, id,
+ 1, name,
+ 2, flags,
+ 3, online,
+ 4, prefailure,
+ 5, current,
+ 6, current_valid,
+ 7, worst,
+ 8, worst_valid,
+ 9, threshold,
+ 10, threshold_valid,
+ 11, good,
+ 12, good_valid,
+ 13, pretty_unit,
+ 14, pretty_value,
+ 15, raw_data,
+ G_MAXUINT);
+
+ g_array_free (raw_data, TRUE);
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
+
typedef struct {
gboolean simulation;
-} DriveRefreshSmartDataData;
+} DriveRefreshAtaSmartDataData;
-static DriveRefreshSmartDataData *
-drive_smart_refresh_data_data_new (gboolean simulation)
+static DriveRefreshAtaSmartDataData *
+drive_ata_smart_refresh_data_data_new (gboolean simulation)
{
- DriveRefreshSmartDataData *data;
- data = g_new0 (DriveRefreshSmartDataData, 1);
+ DriveRefreshAtaSmartDataData *data;
+ data = g_new0 (DriveRefreshAtaSmartDataData, 1);
data->simulation = simulation;
return data;
}
static void
-drive_smart_refresh_data_unref (DriveRefreshSmartDataData *data)
+drive_ata_smart_refresh_data_unref (DriveRefreshAtaSmartDataData *data)
{
g_free (data);
}
/* may be called with context==NULL */
static void
-drive_smart_refresh_data_completed_cb (DBusGMethodInvocation *context,
- DevkitDisksDevice *device,
- PolKitCaller *pk_caller,
- gboolean job_was_cancelled,
- int status,
- const char *stderr,
- const char *stdout,
- gpointer user_data)
-{
- DriveRefreshSmartDataData *data = user_data;
- int rc;
- gboolean passed;
- int n;
- char **lines;
- gboolean in_attributes;
- int power_on_hours;
- int temperature;
- const char *last_self_test_result;
- GTimeVal now;
- gboolean attributes_has_upd;
+drive_ata_smart_refresh_data_completed_cb (DBusGMethodInvocation *context,
+ DevkitDisksDevice *device,
+ PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
+ int status,
+ const char *stderr,
+ const char *stdout,
+ gpointer user_data)
+{
+ DriveRefreshAtaSmartDataData *data;
+ gint rc;
+ gchar **tokens;
+ gboolean ata_smart_is_failing;
+ gboolean ata_smart_is_failing_valid;
+ gboolean ata_smart_has_bad_sectors;
+ gboolean ata_smart_has_bad_attributes;
+ gdouble ata_smart_temperature_kelvin;
+ guint64 ata_smart_power_on_seconds;
+ guint64 ata_smart_time_collected;
+ guint ata_smart_offline_data_collection_status;
+ guint ata_smart_offline_data_collection_seconds;
+ guint ata_smart_self_test_execution_status;
+ guint ata_smart_self_test_execution_percent_remaining;
+ gboolean ata_smart_short_and_extended_self_test_available;
+ gboolean ata_smart_conveyance_self_test_available;
+ gboolean ata_smart_start_self_test_available;
+ gboolean ata_smart_abort_self_test_available;
+ guint ata_smart_short_self_test_polling_minutes;
+ guint ata_smart_extended_self_test_polling_minutes;
+ guint ata_smart_conveyance_self_test_polling_minutes;
GPtrArray *attributes;
+ guint n;
+
+ tokens = NULL;
+
+ data = user_data;
if (job_was_cancelled || stdout == NULL) {
if (job_was_cancelled) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_CANCELLED,
+ "Job was cancelled");
+ } else {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "Error retrieving S.M.A.R.T. data: no output",
+ WEXITSTATUS (status), stderr);
+ }
+ goto out;
+ }
+
+ rc = WEXITSTATUS (status);
+
+ if (rc != 0) {
+ if (rc == 2) {
throw_error (context,
- DEVKIT_DISKS_ERROR_CANCELLED,
- "Job was cancelled");
+ DEVKIT_DISKS_ERROR_ATA_SMART_WOULD_WAKEUP,
+ "Error retrieving S.M.A.R.T. data: %s",
+ stderr);
} else {
throw_error (context,
DEVKIT_DISKS_ERROR_FAILED,
- "Error retrieving S.M.A.R.T. data: no output",
- WEXITSTATUS (status), stderr);
+ "Error retrieving S.M.A.R.T. data: helper failed with exit code %d: %s",
+ rc, stderr);
}
goto out;
}
- rc = WEXITSTATUS (status);
+ g_print ("**************************************************\n");
+ g_print ("TODO: %s parse '%s'\n", device->priv->device_file, stdout);
+ g_print ("**************************************************\n");
- if ((rc & (0x01|0x02|0x04)) != 0) {
- /* update our setting if we "thought" (cf. update_info()) that this device
- * was S.M.A.R.T. capable
- */
- if (device->priv->drive_smart_is_capable) {
- devkit_disks_device_set_drive_smart_is_capable (device, FALSE);
- drain_pending_changes (device, FALSE);
- }
- throw_error (context,
- DEVKIT_DISKS_ERROR_NOT_SMART_CAPABLE,
- "Device is not S.M.A.R.T. capable");
+ tokens = g_strsplit (stdout, "|", 0);
+
+ if (g_strv_length (tokens) < 4) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "malformed data '%s'", stdout);
goto out;
}
- /* TODO: is_enabled */
- devkit_disks_device_set_drive_smart_is_enabled (device, TRUE);
+ if (sscanf (tokens[0],
+ "%" G_GUINT64_FORMAT,
+ &ata_smart_time_collected) != 1) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "error parsing section 0 '%s'", tokens[0]);
+ goto out;
+ }
- g_get_current_time (&now);
- devkit_disks_device_set_drive_smart_time_collected (device, now.tv_sec);
+ if (g_strcmp0 (tokens[1], "atasmartv0") != 0) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "unknown format '%s'", tokens[1]);
+ goto out;
+ }
+ if (sscanf (tokens[2],
+ "%d %d %d %d %lg %" G_GUINT64_FORMAT,
+ &ata_smart_is_failing,
+ &ata_smart_is_failing_valid,
+ &ata_smart_has_bad_sectors,
+ &ata_smart_has_bad_attributes,
+ &ata_smart_temperature_kelvin,
+ &ata_smart_power_on_seconds) != 6) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "error parsing section 2 '%s'", tokens[2]);
+ goto out;
+ }
+
+ if (sscanf (tokens[3],
+ "%d %d %d %d %d %d %d %d %d %d %d",
+ &ata_smart_offline_data_collection_status,
+ &ata_smart_offline_data_collection_seconds,
+ &ata_smart_self_test_execution_status,
+ &ata_smart_self_test_execution_percent_remaining,
+ &ata_smart_short_and_extended_self_test_available,
+ &ata_smart_conveyance_self_test_available,
+ &ata_smart_start_self_test_available,
+ &ata_smart_abort_self_test_available,
+ &ata_smart_short_self_test_polling_minutes,
+ &ata_smart_extended_self_test_polling_minutes,
+ &ata_smart_conveyance_self_test_polling_minutes) != 11) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "error parsing section 3 '%s'", tokens[3]);
+ goto out;
+ }
+
+ devkit_disks_device_set_drive_ata_smart_is_failing (device, ata_smart_is_failing);
+ devkit_disks_device_set_drive_ata_smart_is_failing_valid (device, ata_smart_is_failing_valid);
+ devkit_disks_device_set_drive_ata_smart_has_bad_sectors (device, ata_smart_has_bad_sectors);
+ devkit_disks_device_set_drive_ata_smart_has_bad_attributes (device, ata_smart_has_bad_attributes);
+ devkit_disks_device_set_drive_ata_smart_time_collected (device, ata_smart_time_collected);
+ devkit_disks_device_set_drive_ata_smart_temperature_kelvin (device, ata_smart_temperature_kelvin);
+ devkit_disks_device_set_drive_ata_smart_power_on_seconds (device, ata_smart_power_on_seconds);
+ devkit_disks_device_set_drive_ata_smart_offline_data_collection_status (device, ata_smart_offline_data_collection_status);
+ devkit_disks_device_set_drive_ata_smart_offline_data_collection_seconds (device, ata_smart_offline_data_collection_seconds);
+ devkit_disks_device_set_drive_ata_smart_self_test_execution_status (device, ata_smart_self_test_execution_status);
+ devkit_disks_device_set_drive_ata_smart_self_test_execution_percent_remaining (device, ata_smart_self_test_execution_percent_remaining);
+ devkit_disks_device_set_drive_ata_smart_short_and_extended_self_test_available (device, ata_smart_short_and_extended_self_test_available);
+ devkit_disks_device_set_drive_ata_smart_conveyance_self_test_available (device, ata_smart_conveyance_self_test_available);
+ devkit_disks_device_set_drive_ata_smart_start_self_test_available (device, ata_smart_start_self_test_available);
+ devkit_disks_device_set_drive_ata_smart_abort_self_test_available (device, ata_smart_abort_self_test_available);
+ devkit_disks_device_set_drive_ata_smart_short_self_test_polling_minutes (device, ata_smart_short_self_test_polling_minutes);
+ devkit_disks_device_set_drive_ata_smart_extended_self_test_polling_minutes (device, ata_smart_extended_self_test_polling_minutes);
+ devkit_disks_device_set_drive_ata_smart_conveyance_self_test_polling_minutes (device, ata_smart_conveyance_self_test_polling_minutes);
+
+ /* then all attributes */
attributes = g_ptr_array_new ();
+ for (n = 4; tokens[n] != NULL; n++) {
+ GValue elem = {0};
- passed = TRUE;
- power_on_hours = 0;
- temperature = 0;
- last_self_test_result = "";
-
- if ((rc & 0x08) != 0) {
- passed = FALSE;
- devkit_disks_device_set_drive_smart_is_failing (device, TRUE);
- }
-
- lines = g_strsplit (stdout, "\n", 0);
-
- in_attributes = FALSE;
- attributes_has_upd = FALSE;
- for (n = 0; lines[n] != NULL; n++) {
- const char *line = (const char *) lines[n];
- int id;
- char name[256];
- unsigned int flags;
- int value;
- int worst;
- int threshold;
- char type[256];
- char updated[256];
- char when_failed[256];
- char raw_string_value[256];
- int raw_value;
- int self_test_execution_status;
- gboolean parsed_attr;
-
- /* We're looking at parsing this block of the output
- *
- * ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
- * 1 Raw_Read_Error_Rate 0x000f 200 200 051 Pre-fail Always - 1284
- * 3 Spin_Up_Time 0x0003 225 215 021 Pre-fail Always - 5725
- * 4 Start_Stop_Count 0x0032 100 100 000 Old_age Always - 204
- * 5 Reallocated_Sector_Ct 0x0033 199 199 140 Pre-fail Always - 2
- * 7 Seek_Error_Rate 0x000f 127 127 051 Pre-fail Always - 65877
- * 9 Power_On_Hours 0x0032 096 096 000 Old_age Always - 3429
- * 10 Spin_Retry_Count 0x0013 100 100 051 Pre-fail Always - 0
- * 11 Calibration_Retry_Count 0x0012 100 100 051 Old_age Always - 0
- * 12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always - 153
- * 190 Temperature_Celsius 0x0022 058 032 045 Old_age Always In_the_past 42
- * 194 Temperature_Celsius 0x0022 253 253 000 Old_age Always - 43
- * 196 Reallocated_Event_Count 0x0032 198 198 000 Old_age Always - 2
- * 197 Current_Pending_Sector 0x0012 191 191 000 Old_age Always - 762
- * 198 Offline_Uncorrectable 0x0010 200 200 000 Old_age Offline - 21
- * 199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 40
- * 200 Multi_Zone_Error_Rate 0x0009 170 170 051 Pre-fail Offline - 1542
- *
- */
-
- if (data->simulation) {
- if (strstr (line, "self-assessment test result") != NULL) {
- if (strstr (line, "PASSED") != NULL)
- passed = TRUE;
- else
- passed = FALSE;
- }
+ if (!ata_smart_parse_attribute (tokens[n], &elem)) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "error parsing section %d '%s'", n, tokens[n]);
+ g_ptr_array_foreach (attributes, (GFunc) g_value_array_free, NULL);
+ g_ptr_array_free (attributes, TRUE);
+ goto out;
}
- if (g_str_has_prefix (line, "ID# ATTRIBUTE_NAME ")) {
- in_attributes = TRUE;
- if (strstr (line, "UPDATED") != NULL)
- attributes_has_upd = TRUE;
- continue;
- }
+ g_ptr_array_add (attributes, g_value_get_boxed (&elem));
+ }
- if (strlen (line) >= 256) {
- g_warning ("Ignoring line '%s' (too long)", line);
- continue;
- }
+ devkit_disks_device_set_drive_ata_smart_attributes_steal (device, attributes);
- if (!in_attributes) {
- if (sscanf (line, "Self-test execution status: ( %d)",
- &self_test_execution_status) == 1) {
- //g_warning ("self_test_execution_status: %d", self_test_execution_status);
+ /* emit change event since we've updated the smart data */
+ drain_pending_changes (device, FALSE);
- switch (self_test_execution_status >> 4) {
- case 0:
- last_self_test_result = "completed_ok";
- break;
- case 1:
- last_self_test_result = "not_completed_aborted";
- break;
- case 2:
- last_self_test_result = "not_completed_aborted_reset";
- break;
- case 3:
- last_self_test_result = "not_completed_unknown_reason";
- break;
- case 4:
- last_self_test_result = "completed_failed_unknown_reason";
- break;
- case 5:
- last_self_test_result = "completed_failed_electrical";
- break;
- case 6:
- last_self_test_result = "completed_failed_servo";
- break;
- case 7:
- last_self_test_result = "completed_failed_read";
- break;
- case 8:
- last_self_test_result = "completed_failed_damage";
- break;
- default:
- last_self_test_result = "unknown";
- break;
- }
- devkit_disks_device_set_drive_smart_last_self_test_result (device, last_self_test_result);
+ /* if not simulating, store the retrieved data and do some house-keeping as well
+ *
+ * TODO: it's probably somewhat inefficient to do house-keeping like this (better
+ * to just append to the file and do housekeeping only on startup and every
+ * 24 hours or so)
+ *
+ * TODO: retrieving/storing the data should probably be async as well
+ */
+ if (!data->simulation) {
+ gchar *filename;
+ gchar *contents;
+ gsize length;
+ GError *error;
+ GString *s;
+ time_t now;
+
+ filename = get_ata_smart_filename (device);
+ if (filename == NULL) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "Error computing smart data filename for device");
+ goto out;
+ }
+ error = NULL;
+ if (!g_file_get_contents (filename,
+ &contents,
+ &length,
+ &error)) {
+ if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT) {
+ /* it's ok if the file doesn't exist */
+ g_error_free (error);
+ } else {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "Error retrieving existing SMART data from %s: %s", filename, error->message);
+ g_error_free (error);
+ g_free (filename);
+ goto out;
}
- continue;
}
- if (strlen (line) == 0) {
- break;
- }
+ now = time (NULL);
- parsed_attr = FALSE;
- memset (raw_string_value, '\0', sizeof raw_string_value);
- if (attributes_has_upd) {
- parsed_attr = sscanf (line, "%d %s 0x%x %d %d %d %s %s %s %255c",
- &id, name, &flags, &value, &worst, &threshold,
- type, updated, when_failed, raw_string_value) == 10;
- } else {
- parsed_attr = sscanf (line, "%d %s 0x%x %d %d %d %s %s %255c",
- &id, name, &flags, &value, &worst, &threshold,
- type, when_failed, raw_string_value) == 9;
- }
-
- if (parsed_attr) {
- /*
- g_printerr (" id=%d\n", id);
- g_printerr (" name='%s'\n", name);
- g_printerr (" flags=0x%x\n", flags);
- g_printerr (" value=%d\n", value);
- g_printerr (" worst=%d\n", worst);
- g_printerr (" threshold=%d\n", threshold);
- g_printerr (" type='%s'\n", type);
- g_printerr (" updated='%s'\n", updated);
- g_printerr (" when_failed='%s'\n", when_failed);
- g_printerr (" raw_string_value='%s'\n", raw_string_value);
- */
-
- if (sscanf (raw_string_value, "%d", &raw_value) == 1) {
- if (id == 9) {
- power_on_hours = raw_value;
- devkit_disks_device_set_drive_smart_time_powered_on (device, raw_value * 3600);
- } else if (id == 194) {
- temperature = raw_value;
- devkit_disks_device_set_drive_smart_temperature (device, raw_value);
- }
- }
+ s = g_string_new (NULL);
+ if (contents != NULL) {
+ gchar **lines;
- if (id == 197) {
- }
+ lines = g_strsplit (contents, "\n", 0);
+ for (n = 0; lines[n] != NULL; n++) {
+ time_t time_collected;
- 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_string_value,
- G_MAXUINT);
- g_ptr_array_add (attributes, g_value_get_boxed (&elem));
+ time_collected = (time_t) atoll (lines[n]);
- }
+ /* keep data around for 7 days */
+ if (now - time_collected > 7 * 24 * 60 * 60)
+ continue;
- }
- g_strfreev (lines);
+ g_string_append (s, lines[n]);
+ g_string_append_c (s, '\n');
+ }
+ g_strfreev (lines);
- devkit_disks_device_set_drive_smart_is_failing (device, !passed);
+ g_free (contents);
+ }
- /* this function steals the attributes */
- devkit_disks_device_set_drive_smart_attributes_steal (device, attributes);
+ g_string_append (s, stdout);
- /* emit change event since we've updated the smart data */
- drain_pending_changes (device, FALSE);
+ error = NULL;
+ if (!g_file_set_contents (filename,
+ s->str,
+ s->len,
+ &error)) {
+ if (context != NULL)
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "Error retrieving saving SMART data to %s: %s", filename, error->message);
+ g_error_free (error);
+ g_free (filename);
+ goto out;
+ }
- /* add result to database */
- if (!data->simulation) {
- devkit_disks_logger_record_smart_values (devkit_disks_daemon_local_get_logger (device->priv->daemon),
- device);
+ g_free (filename);
}
if (context != NULL)
- dbus_g_method_return (context, passed, power_on_hours, temperature, last_self_test_result);
+ dbus_g_method_return (context);
out:
- ;
+ g_strfreev (tokens);
}
/* may be called with context==NULL */
gboolean
-devkit_disks_device_drive_smart_refresh_data (DevkitDisksDevice *device,
- char **options,
- DBusGMethodInvocation *context)
+devkit_disks_device_drive_ata_smart_refresh_data (DevkitDisksDevice *device,
+ char **options,
+ DBusGMethodInvocation *context)
{
int n;
char *argv[10];
GError *error;
PolKitCaller *pk_caller;
- const char *simulpath;
+ const char *simuldata;
gboolean nowakeup;
+ uid_t caller_uid;
pk_caller = NULL;
if (context != NULL) {
- if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon,
- context)) == NULL)
+ if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL)
goto out;
}
- if (!device->priv->device_is_drive) {
- throw_error (context, DEVKIT_DISKS_ERROR_NOT_DRIVE,
- "Device is not a drive");
- goto out;
- }
+ if (pk_caller != NULL)
+ polkit_caller_get_uid (pk_caller, &caller_uid);
+ else
+ caller_uid = 0;
- if (!device->priv->drive_smart_is_capable) {
+ if (!device->priv->drive_ata_smart_is_available) {
throw_error (context,
- DEVKIT_DISKS_ERROR_NOT_SMART_CAPABLE,
- "Device is not S.M.A.R.T. capable");
+ DEVKIT_DISKS_ERROR_ATA_SMART_NOT_AVAILABLE,
+ "Device does not support ATA SMART");
goto out;
}
- if (context != NULL) {
+ if (context != NULL && caller_uid != 0) {
if (!devkit_disks_damon_local_check_auth (device->priv->daemon,
pk_caller,
- "org.freedesktop.devicekit.disks.drive-smart-refresh",
+ "org.freedesktop.devicekit.disks.drive-ata-smart-refresh",
context)) {
goto out;
}
}
- simulpath = NULL;
+ simuldata = NULL;
nowakeup = FALSE;
for (n = 0; options[n] != NULL; n++) {
if (g_str_has_prefix (options[n], "simulate=")) {
if (context != NULL) {
- uid_t uid;
- if (!polkit_caller_get_uid (pk_caller, &uid) || uid != 0) {
+ if (caller_uid != 0) {
throw_error (context,
DEVKIT_DISKS_ERROR_FAILED,
"Only uid 0 may use the simulate= option");
goto out;
}
}
- simulpath = (const char *) options[n] + 9;
+ simuldata = (const char *) options[n] + 9;
} else if (strcmp (options[n], "nowakeup") == 0) {
nowakeup = TRUE;
}
}
- if (simulpath != NULL) {
+ if (simuldata != NULL) {
n = 0;
- argv[n++] = "cat";
- argv[n++] = (char *) simulpath;
+ argv[n++] = "echo";
+ argv[n++] = (char *) simuldata;
argv[n++] = NULL;
} else {
n = 0;
- /* TODO: honor option 'nowakeup' */
- argv[n++] = "smartctl";
- argv[n++] = "--all";
+ argv[n++] = PACKAGE_LIBEXEC_DIR "/devkit-disks-helper-ata-smart-collect";
argv[n++] = device->priv->device_file;
+ argv[n++] = nowakeup ? "1" : "0";
argv[n++] = NULL;
}
pk_caller,
argv,
NULL,
- drive_smart_refresh_data_completed_cb,
- drive_smart_refresh_data_data_new (simulpath != NULL),
- (GDestroyNotify) drive_smart_refresh_data_unref)) {
+ drive_ata_smart_refresh_data_completed_cb,
+ drive_ata_smart_refresh_data_data_new (simuldata != NULL),
+ (GDestroyNotify) drive_ata_smart_refresh_data_unref)) {
goto out;
}
/*--------------------------------------------------------------------------------------------------------------*/
+gboolean
+devkit_disks_device_drive_ata_smart_get_historical_data (DevkitDisksDevice *device,
+ guint64 from,
+ guint64 to,
+ DBusGMethodInvocation *context)
+{
+ PolKitCaller *pk_caller;
+ GPtrArray *array;
+ gchar *filename;
+ gchar *contents;
+ GError *error;
+
+ pk_caller = NULL;
+ filename = NULL;
+
+ if (context != NULL) {
+ if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon,
+ context)) == NULL)
+ goto out;
+ }
+
+ if (!device->priv->drive_ata_smart_is_available) {
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_ATA_SMART_NOT_AVAILABLE,
+ "Device does not support ATA SMART");
+ goto out;
+ }
+
+ if (context != NULL) {
+ if (!devkit_disks_damon_local_check_auth (
+ device->priv->daemon,
+ pk_caller,
+ "org.freedesktop.devicekit.disks.drive-ata-smart-retrieve-historical-data",
+ context)) {
+ goto out;
+ }
+ }
+
+ if (from > to) {
+ throw_error (context, DEVKIT_DISKS_ERROR_FAILED, "Malformed time range (from > to)");
+ goto out;
+ }
+
+ to = time (NULL);
+
+ filename = get_ata_smart_filename (device);
+ if (filename == NULL) {
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "Error computing smart data filename for device");
+ goto out;
+ }
+
+ error = NULL;
+ if (!g_file_get_contents (filename,
+ &contents,
+ NULL,
+ &error)) {
+ if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT) {
+ /* it's ok if the file doesn't exist */
+ g_error_free (error);
+ } else {
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_FAILED,
+ "Error retrieving existing SMART data from %s: %s", filename, error->message);
+ g_error_free (error);
+ g_free (filename);
+ goto out;
+ }
+ }
+
+ array = g_ptr_array_new ();
+
+ if (contents != NULL) {
+ gchar **lines;
+ guint n;
+
+ lines = g_strsplit (contents, "\n", 0);
+ for (n = 0; lines[n] != NULL; n++) {
+ gboolean ata_smart_is_failing;
+ gboolean ata_smart_is_failing_valid;
+ gboolean ata_smart_has_bad_sectors;
+ gboolean ata_smart_has_bad_attributes;
+ gdouble ata_smart_temperature_kelvin;
+ guint64 ata_smart_power_on_seconds;
+ guint64 ata_smart_time_collected;
+ gchar **tokens;
+ GPtrArray *attributes;
+ guint m;
+ GValue sample_elem = {0};
+
+ if (strlen (lines[n]) == 0)
+ continue;
+
+ tokens = g_strsplit (lines[n], "|", 0);
+
+ if (sscanf (tokens[0],
+ "%" G_GUINT64_FORMAT,
+ &ata_smart_time_collected) != 1) {
+ g_warning ("error parsing section 0 '%s'", tokens[0]);
+ g_strfreev (tokens);
+ continue;
+ }
+
+ if (! ((ata_smart_time_collected >= from) && (ata_smart_time_collected <= to))) {
+ g_strfreev (tokens);
+ continue;
+ }
+
+ if (g_strcmp0 (tokens[1], "atasmartv0") != 0) {
+ g_warning ("unknown format '%s'", tokens[1]);
+ g_strfreev (tokens);
+ continue;
+ }
+
+ if (sscanf (tokens[2],
+ "%d %d %d %d %lg %" G_GUINT64_FORMAT,
+ &ata_smart_is_failing,
+ &ata_smart_is_failing_valid,
+ &ata_smart_has_bad_sectors,
+ &ata_smart_has_bad_attributes,
+ &ata_smart_temperature_kelvin,
+ &ata_smart_power_on_seconds) != 6) {
+ g_warning ("error parsing section 2 '%s'", tokens[2]);
+ g_strfreev (tokens);
+ continue;
+ }
+
+ attributes = g_ptr_array_new ();
+ for (m = 4; tokens[m] != NULL; m++) {
+ GValue elem = {0};
+
+ /* ignore errors... */
+ if (!ata_smart_parse_attribute (tokens[m], &elem)) {
+ g_warning ("error parsing '%s' in historical data", tokens[m]);
+ continue;
+ }
+
+ g_ptr_array_add (attributes, g_value_get_boxed (&elem));
+ }
+
+ g_value_init (&sample_elem, ATA_SMART_HISTORICAL_SMART_DATA_STRUCT_TYPE);
+ g_value_take_boxed (&sample_elem, dbus_g_type_specialized_construct (ATA_SMART_HISTORICAL_SMART_DATA_STRUCT_TYPE));
+ dbus_g_type_struct_set (&sample_elem,
+ 0, ata_smart_time_collected,
+ 1, ata_smart_is_failing,
+ 2, ata_smart_is_failing_valid,
+ 3, ata_smart_has_bad_sectors,
+ 4, ata_smart_has_bad_attributes,
+ 5, ata_smart_temperature_kelvin,
+ 6, ata_smart_power_on_seconds,
+ 7, attributes,
+ G_MAXUINT);
+ g_ptr_array_add (array, g_value_get_boxed (&sample_elem));
+
+ g_ptr_array_foreach (attributes, (GFunc) g_value_array_free, NULL);
+ g_ptr_array_free (attributes, TRUE);
+
+ g_strfreev (tokens);
+ }
+ g_strfreev (lines);
+
+ g_free (contents);
+ }
+
+
+ dbus_g_method_return (context, array);
+
+ g_ptr_array_foreach (array, (GFunc) g_value_array_free, NULL);
+ g_ptr_array_free (array, TRUE);
+
+out:
+ g_free (filename);
+ if (pk_caller != NULL)
+ polkit_caller_unref (pk_caller);
+ return TRUE;
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
+
static void
-drive_smart_initiate_selftest_completed_cb (DBusGMethodInvocation *context,
- DevkitDisksDevice *device,
- PolKitCaller *pk_caller,
- gboolean job_was_cancelled,
- int status,
- const char *stderr,
- const char *stdout,
- gpointer user_data)
+drive_ata_smart_initiate_selftest_completed_cb (DBusGMethodInvocation *context,
+ DevkitDisksDevice *device,
+ PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
+ int status,
+ const char *stderr,
+ const char *stdout,
+ gpointer user_data)
{
+ char *options[] = {NULL};
+
+ /* no matter what happened, refresh the data */
+ devkit_disks_device_drive_ata_smart_refresh_data (device, options, NULL);
+
if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
dbus_g_method_return (context);
}
gboolean
-devkit_disks_device_drive_smart_initiate_selftest (DevkitDisksDevice *device,
- const char *test,
- gboolean captive,
- DBusGMethodInvocation *context)
+devkit_disks_device_drive_ata_smart_initiate_selftest (DevkitDisksDevice *device,
+ const char *test,
+ gchar **options,
+ DBusGMethodInvocation *context)
{
int n;
char *argv[10];
if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL)
goto out;
- if (!device->priv->device_is_drive) {
- throw_error (context, DEVKIT_DISKS_ERROR_NOT_DRIVE,
- "Device is not a drive");
+ if (!device->priv->drive_ata_smart_is_available) {
+ throw_error (context,
+ DEVKIT_DISKS_ERROR_ATA_SMART_NOT_AVAILABLE,
+ "Device does not support ATA SMART");
goto out;
}
- if (captive) {
- if (devkit_disks_device_local_is_busy (device)) {
- throw_error (context, DEVKIT_DISKS_ERROR_BUSY,
- "Device is busy");
- goto out;
- }
-
- if (devkit_disks_device_local_partitions_are_busy (device)) {
- throw_error (context, DEVKIT_DISKS_ERROR_BUSY,
- "A partition on the device is busy");
- goto out;
- }
- }
-
if (!devkit_disks_damon_local_check_auth (device->priv->daemon,
pk_caller,
- "org.freedesktop.devicekit.disks.drive-smart-selftest",
+ "org.freedesktop.devicekit.disks.drive-ata-smart-selftest",
context)) {
goto out;
}
n = 0;
- argv[n++] = PACKAGE_LIBEXEC_DIR "/devkit-disks-helper-smart-selftest";
+ argv[n++] = PACKAGE_LIBEXEC_DIR "/devkit-disks-helper-ata-smart-selftest";
argv[n++] = device->priv->device_file;
argv[n++] = (char *) test;
- argv[n++] = captive ? "1" : "0";
argv[n++] = NULL;
error = NULL;
if (!job_new (context,
- "DriveSmartInitiateSelftest",
+ "DriveAtaSmartInitiateSelftest",
TRUE,
device,
pk_caller,
argv,
NULL,
- drive_smart_initiate_selftest_completed_cb,
+ drive_ata_smart_initiate_selftest_completed_cb,
NULL,
NULL)) {
goto out;
const char *new_label,
DBusGMethodInvocation *context);
-gboolean devkit_disks_device_drive_smart_refresh_data (DevkitDisksDevice *device,
- 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,
- DBusGMethodInvocation *context);
+gboolean devkit_disks_device_drive_ata_smart_refresh_data (DevkitDisksDevice *device,
+ char **options,
+ DBusGMethodInvocation *context);
+
+gboolean devkit_disks_device_drive_ata_smart_get_historical_data (DevkitDisksDevice *device,
+ guint64 from,
+ guint64 to,
+ DBusGMethodInvocation *context);
+
+gboolean devkit_disks_device_drive_ata_smart_initiate_selftest (DevkitDisksDevice *device,
+ const char *test,
+ char **options,
+ DBusGMethodInvocation *context);
gboolean devkit_disks_device_linux_md_stop (DevkitDisksDevice *device,
char **options,
+++ /dev/null
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2008 David Zeuthen <david@fubar.dk>
- *
- * 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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <glib/gi18n-lib.h>
-#include <glib-object.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <sqlite3.h>
-
-#include "devkit-disks-daemon.h"
-#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_DISKS_TYPE_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_DISKS_TYPE_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->drive_vendor == NULL || strlen (device->priv->drive_vendor) == 0)
- goto out;
- if (device->priv->drive_model == NULL || strlen (device->priv->drive_model) == 0)
- goto out;
- if (device->priv->drive_revision == NULL || strlen (device->priv->drive_revision) == 0)
- goto out;
- if (device->priv->drive_serial == NULL || strlen (device->priv->drive_serial) == 0)
- goto out;
-
- s = g_strdup_printf ("%s_%s_%s_%s",
- device->priv->drive_vendor,
- device->priv->drive_model,
- device->priv->drive_revision,
- device->priv->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_ERROR,
- error_code,
- "%s", 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;
- PolKitCaller *pk_caller;
-
- disk_id = NULL;
- pk_caller = NULL;
-
- if (context != NULL) {
- if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon,
- context)) == NULL)
- goto out;
- }
-
- if (context != NULL) {
- if (!devkit_disks_damon_local_check_auth (
- device->priv->daemon,
- pk_caller,
- "org.freedesktop.devicekit.disks.drive-smart-retrieve-historical-data",
- context)) {
- goto out;
- }
- }
-
- 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_ERROR_FAILED, "No unique disk id for device");
- goto out;
- }
-
- if (from > to) {
- throw_error (context, DEVKIT_DISKS_ERROR_FAILED, "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);
- if (pk_caller != NULL)
- polkit_caller_unref (pk_caller);
- return TRUE;
-}
+++ /dev/null
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2008 David Zeuthen <david@fubar.dk>
- *
- * 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 "devkit-disks-types.h"
-
-G_BEGIN_DECLS
-
-#define DEVKIT_DISKS_TYPE_LOGGER (devkit_disks_logger_get_type ())
-#define DEVKIT_DISKS_LOGGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_DISKS_TYPE_LOGGER, DevkitDisksLogger))
-#define DEVKIT_DISKS_LOGGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_DISKS_TYPE_LOGGER, DevkitDisksLoggerClass))
-#define DEVKIT_DISKS_IS_LOGGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_DISKS_TYPE_LOGGER))
-#define DEVKIT_DISKS_IS_LOGGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_DISKS_TYPE_LOGGER))
-#define DEVKIT_DISKS_LOGGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_DISKS_TYPE_LOGGER, DevkitDisksLoggerClass))
-
-typedef struct DevkitDisksLoggerClass DevkitDisksLoggerClass;
-typedef struct DevkitDisksLoggerPrivate DevkitDisksLoggerPrivate;
-
-struct DevkitDisksLogger
-{
- GObject parent;
- DevkitDisksLoggerPrivate *priv;
-};
-
-struct DevkitDisksLoggerClass
-{
- GObjectClass parent_class;
-};
-
-GType devkit_disks_logger_get_type (void) G_GNUC_CONST;
-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__ */
typedef struct DevkitDisksDaemon DevkitDisksDaemon;
typedef struct DevkitDisksDevice DevkitDisksDevice;
-typedef struct DevkitDisksLogger DevkitDisksLogger;
typedef struct DevkitDisksMount DevkitDisksMount;
typedef struct DevkitDisksMountMonitor DevkitDisksMountMonitor;
typedef struct DevkitDisksInhibitor DevkitDisksInhibitor;
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 David Zeuthen <david@fubar.dk>
+ *
+ * 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
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <glib.h>
+#include <atasmart.h>
+
+static void
+usage (void)
+{
+ fprintf (stderr, "incorrect usage\n");
+}
+
+static guint64 temperature_mkelvin;
+static gboolean has_bad_sectors;
+static gboolean has_bad_attributes;
+static guint64 power_on_seconds;
+
+
+static void
+collect_attrs (SkDisk *d, const SkSmartAttributeParsedData *a, void *user_data)
+{
+ GList **list = user_data;
+ GString *s;
+
+ s = g_string_new (NULL);
+
+ if (strcmp (a->name, "temperature-centi-celsius") == 0 ||
+ strcmp (a->name, "temperature-celsius") == 0 ||
+ strcmp (a->name, "temperature-celsius-2") == 0 ||
+ strcmp (a->name, "airflow-temperature-celsius") == 0) {
+ temperature_mkelvin = a->pretty_value;
+ }
+
+ if (strcmp (a->name, "power-on-minutes") == 0 ||
+ strcmp (a->name, "power-on-seconds") == 0 ||
+ strcmp (a->name, "power-on-half-minutes") == 0 ||
+ strcmp (a->name, "power-on-hours") == 0) {
+ power_on_seconds = a->pretty_value / 1000;
+ }
+
+ if (strcmp (a->name, "reallocated-sector-count") ==0 ||
+ strcmp (a->name, "current-pending-sector") == 0 ||
+ strcmp (a->name, "reallocated-event-count") == 0) {
+ if (a->pretty_value > 0)
+ has_bad_sectors = TRUE;
+ }
+
+ if (!a->good)
+ has_bad_attributes = TRUE;
+
+ g_string_append_printf (s,
+ "%d " /* id */
+ "%s " /* name */
+ "%d " /* flags */
+ "%d %d " /* online, prefailure */
+ "%d %d " /* current_value, current_value_valid */
+ "%d %d " /* worst_value, worst_value_valid */
+ "%d %d " /* threshold, threshold_valid */
+ "%d %d " /* good, good_valid */
+ "%d %" G_GUINT64_FORMAT " " /* pretty_unit, pretty_value */
+ "%02x %02x %02x %02x %02x %02x", /* raw[6] */
+
+ a->id,
+ a->name,
+ a->flags,
+ a->online, a->prefailure,
+
+ a->current_value, a->current_value_valid,
+ a->worst_value, a->worst_value_valid,
+ a->threshold, a->threshold_valid,
+ a->good, a->good_valid,
+
+ a->pretty_unit, a->pretty_value,
+
+ a->raw[0], a->raw[1], a->raw[2], a->raw[3], a->raw[4], a->raw[5]);
+
+ *list = g_list_prepend (*list, g_string_free (s, FALSE));
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+ const char *device;
+ SkDisk *d;
+ SkBool smart_is_available;
+ SkBool awake;
+ SkBool good;
+ const SkSmartParsedData *data;
+ GString *s;
+ GList *attrs;
+ GList *l;
+ gboolean nowakeup;
+
+ d = NULL;
+ attrs = NULL;
+ ret = 1;
+
+ s = g_string_new (NULL);
+
+ if (argc != 3) {
+ usage ();
+ goto out;
+ }
+
+ device = argv[1];
+
+ nowakeup = atoi (argv[2]);
+
+ if (sk_disk_open (device, &d) != 0) {
+ fprintf (stderr, "Failed to open disk %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ if (sk_disk_check_sleep_mode (d, &awake) != 0) {
+ fprintf (stderr, "Failed to check if disk %s is awake: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ /* don't wake up disk unless specically asked to */
+ if (nowakeup && !awake) {
+ fprintf (stderr, "Disk %s is asleep and nowakeup option was passed\n", device);
+ ret = 2;
+ goto out;
+ }
+
+ if (sk_disk_smart_is_available (d, &smart_is_available) != 0) {
+ fprintf (stderr, "Failed to determine if smart is available for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ /* time collected */
+ g_string_append_printf (s, "%" G_GUINT64_FORMAT "|", (guint64) time (NULL));
+
+ /* version of data */
+ g_string_append_printf (s, "atasmartv0");
+
+ /* main smart data */
+ if (sk_disk_smart_read_data (d) != 0) {
+ fprintf (stderr, "Failed to read smart data for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+ if (sk_disk_smart_parse (d, &data) != 0) {
+ fprintf (stderr, "Failed to parse smart data for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ temperature_mkelvin = 0;
+ has_bad_sectors = FALSE;
+ has_bad_attributes = FALSE;
+ power_on_seconds = 0;
+
+ if (sk_disk_smart_parse_attributes (d, collect_attrs, &attrs) != 0) {
+ fprintf (stderr, "Failed to parse smart attributes for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+ attrs = g_list_reverse (attrs);
+
+ /* health status
+ *
+ * note that this is allowed to fail; some USB disks don't report status
+ */
+ if (sk_disk_smart_status (d, &good) != 0) {
+ fprintf (stderr, "Failed to read smart status for %s: %s\n", device, strerror (errno));
+ g_string_append (s, "|1 0");
+ } else {
+ g_string_append_printf (s, "|%d 1", good ? 0 : 1);
+ }
+ g_string_append_printf (s, " %d %d %lg %" G_GUINT64_FORMAT,
+ has_bad_sectors,
+ has_bad_attributes,
+ temperature_mkelvin / 1000.0,
+ power_on_seconds);
+
+ g_string_append_printf (s,
+ "|%d %d %d %d "
+ "%d %d %d %d "
+ "%d %d %d",
+ data->offline_data_collection_status,
+ data->total_offline_data_collection_seconds,
+ data->self_test_execution_status,
+ data->self_test_execution_percent_remaining,
+ data->short_and_extended_test_available,
+ data->conveyance_test_available,
+ data->start_test_available,
+ data->abort_test_available,
+ data->short_test_polling_minutes,
+ data->extended_test_polling_minutes,
+ data->conveyance_test_polling_minutes);
+
+ /* then each attribute */
+ for (l = attrs; l != NULL; l = l->next) {
+ g_string_append (s, "|");
+ g_string_append (s, l->data);
+ }
+
+ printf ("%s\n", s->str);
+
+ ret = 0;
+
+ out:
+ g_string_free (s, TRUE);
+ g_list_foreach (attrs, (GFunc) g_free, FALSE);
+ g_list_free (attrs);
+
+ if (d != NULL)
+ sk_disk_free (d);
+ return ret;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 David Zeuthen <david@fubar.dk>
+ *
+ * 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
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <atasmart.h>
+
+static void
+usage (void)
+{
+ g_printerr ("incorrect usage\n");
+}
+
+static const gchar *device;
+static gboolean cancelled = FALSE;
+
+static void
+sigterm_handler (int signum)
+{
+ cancelled = TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+ SkDisk *d;
+ SkBool smart_is_available;
+ SkSmartSelfTest test;
+ const gchar *taskname;
+
+ d = NULL;
+ ret = 1;
+
+ if (argc != 3) {
+ usage ();
+ goto out;
+ }
+
+ device = argv[1];
+
+ if (strcmp (argv[2], "short") == 0) {
+ test = SK_SMART_SELF_TEST_SHORT;
+ taskname = "ata_smart_selftest_short";
+ } else if (strcmp (argv[2], "extended") == 0) {
+ test = SK_SMART_SELF_TEST_EXTENDED;
+ taskname = "ata_smart_selftest_extended";
+ } else if (strcmp (argv[2], "conveyance") == 0) {
+ test = SK_SMART_SELF_TEST_CONVEYANCE;
+ taskname = "ata_smart_selftest_conveyance";
+ } else {
+ g_printerr ("Unknown test '%s'\n", argv[2]);
+ goto out;
+ }
+
+ if (sk_disk_open (device, &d) != 0) {
+ g_printerr ("Failed to open disk %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ if (sk_disk_smart_is_available (d, &smart_is_available) != 0) {
+ g_printerr ("Failed to determine if smart is available for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ /* if the user cancels, catch that and abort the test */
+ signal (SIGTERM, sigterm_handler);
+
+ /* progress at 0% initially */
+ g_print ("progress: 0 1 0 %s\n", taskname);
+
+ /* start the test */
+ if (sk_disk_smart_self_test (d, test) != 0) {
+ g_printerr ("Error initiating test on disk %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ /* poll for completion */
+ while (TRUE && !cancelled) {
+ const SkSmartParsedData *data;
+
+ sleep (2);
+
+ if (sk_disk_smart_read_data (d) != 0) {
+ g_printerr ("Failed to read smart data for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+ if (sk_disk_smart_parse (d, &data) != 0) {
+ g_printerr ("Failed to parse smart data for %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+
+ if (data->self_test_execution_status != SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS)
+ break;
+
+ /* update progress */
+ g_print ("progress: 0 1 %d %s\n", 100 - data->self_test_execution_percent_remaining, taskname);
+ }
+
+ /* abort test if cancelled */
+ if (cancelled) {
+ if (sk_disk_smart_self_test (d, SK_SMART_SELF_TEST_ABORT) != 0) {
+ g_printerr ("Error cancelling test on disk %s: %s\n", device, strerror (errno));
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+ out:
+ if (d != NULL)
+ sk_disk_free (d);
+ return ret;
+}
+++ /dev/null
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2008 David Zeuthen <david@fubar.dk>
- *
- * 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
-
-#define _LARGEFILE64_SOURCE
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-#include <glib.h>
-
-#include "job-shared.h"
-
-static const char *device;
-static gboolean cancelled = FALSE;
-
-static void
-sigterm_handler (int signum)
-{
- cancelled = TRUE;
-}
-
-static gboolean
-abort_test (void)
-{
- gboolean ret;
- int exit_status;
- char *standard_error;
- char *command_line;
- GError *error;
-
- ret = FALSE;
-
- command_line = g_strdup_printf ("smartctl -X %s", device);
-
- error = NULL;
- if (!g_spawn_command_line_sync (command_line,
- NULL,
- &standard_error,
- &exit_status,
- &error)) {
- g_printerr ("cannot spawn '%s': %s\n", command_line, error->message);
- g_error_free (error);
- goto out;
- }
- if (WEXITSTATUS (exit_status) != 0) {
- g_printerr ("helper failed with:\n%s", standard_error);
- goto out;
- }
- g_free (standard_error);
-
- ret = TRUE;
-
-out:
- return ret;
-}
-
-int
-main (int argc, char **argv)
-{
- int ret;
- int exit_status;
- GError *error;
- char *command_line;
- char *standard_output;
- char *standard_error;
- const char *test;
- gboolean captive;
- const char *result;
- const char *taskname;
-
- ret = 1;
- command_line = NULL;
- standard_error = NULL;
- result = NULL;
-
- if (argc != 4) {
- g_printerr ("wrong usage\n");
- goto out;
- }
- device = argv[1];
- test = argv[2];
- captive = (strcmp (argv[3], "1") == 0);
-
- if (strcmp (test, "short") == 0) {
- taskname = "smartselftest_short";
- } else if (strcmp (test, "long") == 0) {
- taskname = "smartselftest_long";
- } else {
- g_printerr ("unknown test '%s'", test);
- goto out;
- }
-
- g_print ("device = '%s'\n", device);
- g_print ("test = '%s'\n", test);
- g_print ("captive = %d\n", captive);
-
- command_line = g_strdup_printf ("smartctl -t %s %s %s",
- test,
- captive ? "-C" : "",
- device);
-
- error = NULL;
- if (!g_spawn_command_line_sync (command_line,
- NULL,
- &standard_error,
- &exit_status,
- &error)) {
- g_printerr ("cannot spawn '%s'\n", command_line);
- goto out;
- }
- if (WEXITSTATUS (exit_status) != 0) {
- g_printerr ("helper failed with:\n%s", standard_error);
- goto out;
- }
- g_free (standard_error);
- standard_error = NULL;
-
- signal (SIGTERM, sigterm_handler);
-
- /* ok, now poll every five secs via 'smartctl -c' until the test is done */
-
- g_free (command_line);
- command_line = g_strdup_printf ("smartctl -c %s", device);
-
-
- /* progress at 0% initially */
- g_print ("progress: 0 1 0 %s\n", taskname);
-
- while (TRUE) {
- int n;
- char **lines;
- int percentage_done;
- int exec_status = -1;
-
- sleep (5);
-
- if (cancelled) {
- g_printerr ("Aborting test and exiting since we caught SIGTERM\n");
- abort_test ();
- goto out;
- }
-
- error = NULL;
- if (!g_spawn_command_line_sync (command_line,
- &standard_output,
- &standard_error,
- &exit_status,
- &error)) {
- g_printerr ("cannot spawn '%s'\n", command_line);
- goto out;
- }
- if (WEXITSTATUS (exit_status) != 0) {
- g_printerr ("helper failed with:\n%s", standard_error);
- goto out;
- }
- g_free (standard_error);
- standard_error = NULL;
-
- lines = g_strsplit (standard_output, "\n", 0);
- for (n = 0; lines[n] != NULL; n++) {
- const char *line = (const char *) lines[n];
- if (g_str_has_prefix (line, "Self-test execution status:")) {
- int m;
-
- for (m = 0; line[m] != '\0'; m++) {
- if (g_ascii_isdigit (line[m]))
- break;
- }
- if (line[m] != '\0') {
- char *endp;
-
- exec_status = strtol (line + m, &endp, 10);
- if (*endp == ')') {
- /* good */
- } else {
- exec_status = -1;
- }
- }
- }
- }
- g_strfreev (lines);
-
- /* didn't manage to parse output */
- if (exec_status == -1) {
- g_printerr ("Unexpected output polling drive for selftest completion\n");
- abort_test ();
- goto out;
- }
-
- /* see ataprint.cpp:ataPrintSelectiveSelfTestLog() in smartmontools */
-
- if ((exec_status >> 4) == 15) {
- percentage_done = 100 - (exec_status & 0x0f) * 10;
- g_print ("progress: 0 1 %d %s\n", percentage_done, taskname);
- } else {
- switch ((exec_status)>>4){
- case 0:
- result = "Completed";
- break;
- case 1:
- result = "Aborted_by_host";
- break;
- case 2:
- result = "Interrupted";
- break;
- case 3:
- result = "Fatal_error";
- break;
- case 4:
- result = "Completed_unknown_failure";
- break;
- case 5:
- result = "Completed_electrical_failure";
- break;
- case 6:
- result = "Completed_servo/seek_failure";
- break;
- case 7:
- result = "Completed_read_failure";
- break;
- case 8:
- result = "Completed_handling_damage??";
- break;
- default:
- g_printerr ("Unexpected status %d polling drive for selftest completion\n",
- exec_status);
- abort_test ();
- goto out;
- }
- goto test_complete;
- }
- }
-
-test_complete:
- /* send the result of the test back to the daemon */
- /* g_printerr ("job-smart-selftest: %s\n", result); */
- ret = 0;
-
-out:
- g_free (standard_error);
- g_free (command_line);
- return ret;
-}
<!ENTITY ERROR_NOT_LINUX_MD "org.freedesktop.DeviceKit.Disks.Error.NotLinuxMd">
<!ENTITY ERROR_NOT_LINUX_MD_COMPONENT "org.freedesktop.DeviceKit.Disks.Error.NotLinuxMdComponent">
<!ENTITY ERROR_NOT_DRIVE "org.freedesktop.DeviceKit.Disks.Error.NotDrive">
- <!ENTITY ERROR_NOT_SMART_CAPABLE "org.freedesktop.DeviceKit.Disks.Error.NotSmartCapable">
<!ENTITY ERROR_NOT_SUPPORTED "org.freedesktop.DeviceKit.Disks.Error.NotSupported">
<!ENTITY ERROR_NOT_FOUND "org.freedesktop.DeviceKit.Disks.Error.NotFound">
+ <!ENTITY ERROR_ATA_SMART_NOT_AVAILABLE "org.freedesktop.DeviceKit.Disks.Error.AtaSmartNotAvailable">
+ <!ENTITY ERROR_ATA_SMART_WOULD_WAKEUP "org.freedesktop.DeviceKit.Disks.Error.AtaSmartWouldWakeup">
<!ENTITY ERROR_NOT_AUTHORIZED "org.freedesktop.PolicyKit.Error.NotAuthorized">
]>
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<!-- ************************************************************ -->
- <method name="DriveSmartRefreshData">
+ <method name="DriveAtaSmartRefreshData">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="options" direction="in" type="as">
<doc:doc><doc:summary>
The option <doc:tt>nowakeup</doc:tt> can be passed to
avoid spinning up the disk if it's in a low-power mode.
- The option <doc:tt>simulate=/path/to/smartctl-output</doc:tt> can be
- passed to read the given file instead of invoking <doc:tt>smartctl(8)</doc:tt> tool.
+ The option <doc:tt>simulate=</doc:tt> can be
+ passed to use the given string (which is in a format private to DeviceKit-disks) instead
+ of reading it from the disk.
The <doc:tt>simulate=</doc:tt> option can only be used by the super user.
</doc:summary></doc:doc>
</arg>
<doc:description>
<doc:para>
Refreshes the
- <doc:ulink url="http://en.wikipedia.org/wiki/S.M.A.R.T">S.M.A.R.T.</doc:ulink>
+ <doc:ulink url="http://en.wikipedia.org/wiki/S.M.A.R.T">ATA SMART</doc:ulink>
data for the given drive. Note that this operation is not run as a job.
</doc:para>
</doc:description>
The caller will need one of the following PolicyKit authorizations:
<doc:list>
<doc:item>
- <doc:term>org.freedesktop.devicekit.disks.drive-smart-refresh</doc:term>
- <doc:definition>Needed to refresh S.M.A.R.T. data</doc:definition>
+ <doc:term>org.freedesktop.devicekit.disks.drive-ata-smart-refresh</doc:term>
+ <doc:definition>Needed to refresh ATA SMART data</doc:definition>
</doc:item>
</doc:list>
</doc:permission>
<doc:errors>
<doc:error name="&ERROR_NOT_AUTHORIZED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
- <doc:error name="&ERROR_BUSY;">component to add is busy</doc:error>
+ <doc:error name="&ERROR_ATA_SMART_NOT_AVAILABLE;">if ATA SMART isn't available on the disk</doc:error>
+ <doc:error name="&ERROR_ATA_SMART_WOULD_WAKEUP;">If the disk is asleep and the nowakeup option was passed</doc:error>
<doc:error name="&ERROR_FAILED;">if incoming parameters are invalid or an unknown error occured</doc:error>
- <doc:error name="&ERROR_NOT_SMART_CAPABLE;">device is not S.M.A.R.T. capable</doc:error>
- <doc:error name="&ERROR_NOT_DRIVE;">device is not a drive</doc:error>
</doc:errors>
</doc:doc>
</method>
- <method name="DriveSmartGetHistoricalData">
+ <!-- ************************************************************ -->
+
+ <method name="DriveAtaSmartGetHistoricalData">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="since" direction="in" type="t">
<doc:doc><doc:summary>
- Don't fetch S.M.A.R.T. data collected earlier than this point
+ Don't fetch data collected earlier than this point
in time (seconds since the Epoch Jan 1, 1970 0:00 UTC).
</doc:summary></doc:doc>
</arg>
<arg name="until" direction="in" type="t">
<doc:doc><doc:summary>
- Don't fetch S.M.A.R.T. data collected later than this point in
+ Don't fetch 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.
</doc:summary></doc:doc>
</arg>
- <arg name="data" direction="out" type="a(tdtsba(isiiiis))">
+ <arg name="data" direction="out" type="a(tbbbbdta(usubbybybybbbutay))">
<doc:doc><doc:summary>
- An array of historical S.M.A.R.T. data. Each element contains
- the following members:
- <doc:list>
- <doc:item>
- <doc:term>time</doc:term>
- <doc:definition>
- When the data was collected (seconds since the Epoch Jan 1, 1970 0:00 UTC). Similar to the
- <doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
- property.
- </doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>temperature</doc:term>
- <doc:definition>
- Temperature of the drive. Similar to the
- <doc:ref type="property" to="Device:drive-smart-temperature">drive-smart-temperature</doc:ref>
- property.
- </doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>time-powered-on</doc:term>
- <doc:definition>
- Number of the seconds the drive has been powered on. Similar to the
- <doc:ref type="property" to="Device:drive-smart-time-powered-on">drive-smart-time-powered-on</doc:ref>
- property.
- </doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>last-self-test-result</doc:term>
- <doc:definition>
- The result of the last self-test. Similar to the
- <doc:ref type="property" to="Device:drive-smart-last-self-test-result">drive-smart-last-self-test-result</doc:ref>
- property.
- </doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>is-failing</doc:term>
- <doc:definition>
- If the drive is assessed to be failing. Similar to the
- <doc:ref type="property" to="Device:drive-smart-is-failing">drive-smart-is-failing</doc:ref>
- property.
- </doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>attributes</doc:term>
- <doc:definition>
- The attributes of the drive. Similar to the
- <doc:ref type="property" to="Device:drive-smart-attributes">drive-smart-attributes</doc:ref>
- property.
- </doc:definition>
- </doc:item>
- </doc:list>
+ An array of historical data. Each element contains
+ the following members (TODO).
</doc:summary></doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>
- Retrieves historical S.M.A.R.T. data from the drive in the
+ Retrieves historical ATA SMART 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.
+ stored by the host as ATA SMART capable devices cannot
+ store or return historical data by themselves.
</doc:para>
</doc:description>
<doc:permission>
The caller will need one of the following PolicyKit authorizations:
<doc:list>
<doc:item>
- <doc:term>org.freedesktop.devicekit.disks.drive-smart-retrieve-historical-data</doc:term>
- <doc:definition>To retrieve historical S.M.A.R.T. data</doc:definition>
+ <doc:term>org.freedesktop.devicekit.disks.drive-ata-smart-retrieve-historical-data</doc:term>
+ <doc:definition>To retrieve historical ATA SMART data</doc:definition>
</doc:item>
</doc:list>
</doc:permission>
<doc:errors>
<doc:error name="&ERROR_NOT_AUTHORIZED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
- <doc:error name="&ERROR_BUSY;">component to add is busy</doc:error>
+ <doc:error name="&ERROR_ATA_SMART_NOT_AVAILABLE;">if ATA SMART isn't available on the disk</doc:error>
<doc:error name="&ERROR_FAILED;">if incoming parameters are invalid or an unknown error occured</doc:error>
<doc:error name="&ERROR_CANCELLED;">if the job was cancelled</doc:error>
- <doc:error name="&ERROR_NOT_SMART_CAPABLE;">device is not S.M.A.R.T. capable</doc:error>
- <doc:error name="&ERROR_NOT_DRIVE;">device is not a drive</doc:error>
</doc:errors>
</doc:doc>
</method>
<!-- ************************************************************ -->
- <method name="DriveSmartInitiateSelftest">
+ <method name="DriveAtaSmartInitiateSelftest">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="test" direction="in" type="s">
<doc:doc><doc:summary>
The name of the test to run; supported values are 'short'
- (usually less than ten minutes) and 'long' (usually tens
- of minutes) and 'conveyance' (usually a few minutes). See
- the smartctl(1) man page for details.
+ (usually less than ten minutes), 'extended' (usually tens
+ of minutes) and 'conveyance' (usually a few minutes).
</doc:summary></doc:doc>
</arg>
- <arg name="captive" direction="in" type="b">
- <doc:doc><doc:summary>
- If TRUE then the drive will block access to the drive for
- the duration of the test. The method will error out if the
- drive is busy, e.g. if partitions are mounted.
- </doc:summary></doc:doc>
+ <arg name="options" direction="in" type="as">
+ <doc:doc><doc:summary>Currently unused.</doc:summary></doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>
- Runs a S.M.A.R.T. self test on the drive. TODO: need to figure out whether we need a return code.
+ Runs a ATA SMART self test on the drive.
</doc:para>
</doc:description>
<doc:permission>
The caller will need one of the following PolicyKit authorizations:
<doc:list>
<doc:item>
- <doc:term>org.freedesktop.devicekit.disks.drive-smart-selftest</doc:term>
- <doc:definition>Needed to run S.M.A.R.T. self tests</doc:definition>
+ <doc:term>org.freedesktop.devicekit.disks.drive-ata-smart-selftest</doc:term>
+ <doc:definition>Needed to run ATA SMART self tests</doc:definition>
</doc:item>
</doc:list>
</doc:permission>
<doc:errors>
<doc:error name="&ERROR_NOT_AUTHORIZED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
- <doc:error name="&ERROR_BUSY;">component to add is busy</doc:error>
<doc:error name="&ERROR_FAILED;">if incoming parameters are invalid or an unknown error occured</doc:error>
<doc:error name="&ERROR_CANCELLED;">if the job was cancelled</doc:error>
- <doc:error name="&ERROR_NOT_SMART_CAPABLE;">device is not S.M.A.R.T. capable</doc:error>
- <doc:error name="&ERROR_NOT_DRIVE;">device is not a drive</doc:error>
+ <doc:error name="&ERROR_ATA_SMART_NOT_AVAILABLE;">device is not ATA SMART capable</doc:error>
</doc:errors>
</doc:doc>
</method>
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-is-capable" type="b" access="read">
+ <!-- **************************************************************************************************** -->
+
+ <property name="drive-ata-smart-is-available" type="b" access="read">
<doc:doc><doc:description><doc:para>
- TRUE only if drive is
- <doc:ulink url="http://en.wikipedia.org/wiki/S.M.A.R.T">S.M.A.R.T.</doc:ulink>
- capable.
+ TRUE only if drive is capable of reporting
+ <doc:ulink url="http://en.wikipedia.org/wiki/S.M.A.R.T">ATA SMART</doc:ulink>
+ data.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-is-enabled" type="b" access="read">
+ <property name="drive-ata-smart-is-failing" type="b" access="read">
<doc:doc><doc:description><doc:para>
- TRUE only if S.M.A.R.T. is enabled for the drive.
+ Set to TRUE if ATA SMART indicates that the disk is failing, TRUE otherwise.
This property is only valid if
- <doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero and the property
+ <doc:ref type="property" to="Device:drive-ata-smart-status-valid">drive-ata-smart-status-valid</doc:ref>
+ is TRUE.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-is-failing-valid" type="b" access="read">
+ <doc:doc><doc:description><doc:para>
+ Set to TRUE only if the property
+ <doc:ref type="property" to="Device:drive-ata-smart-status">drive-ata-smart-status</doc:ref>
+ is valid.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-has-bad-sectors" type="b" access="read">
+ <doc:doc><doc:description><doc:para>
+ Set to TRUE if ATA SMART indicates that one or more sectors are bad, TRUE otherwise.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-has-bad-attributes" type="b" access="read">
+ <doc:doc><doc:description><doc:para>
+ Set to TRUE if ATA SMART indicates that one or more attributes are exceeding their threshold, TRUE otherwise.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-temperature-kelvin" type="d" access="read">
+ <doc:doc><doc:description><doc:para>
+ Temperature of the drive in kelvin or 0 if unknown.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-power-on-seconds" type="t" access="read">
+ <doc:doc><doc:description><doc:para>
+ Seconds the drive has been powered on or 0 if unknown.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
is greater than zero.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-time-collected" type="t" access="read">
+ <property name="drive-ata-smart-time-collected" type="t" access="read">
<doc:doc><doc:description><doc:para>
The point in time (seconds since the Epoch Jan 1, 1970
- 0:00 UTC) when the S.M.A.R.T. data was collected. If data
+ 0:00 UTC) when ATA SMART data was collected. If data
was never collected, this property will assume the value
0. This property is only valid if
- <doc:ref type="property" to="Device:drive-smart-is-capable">drive-smart-is-capable</doc:ref>
+ <doc:ref type="property" to="Device:drive-ata-smart-is-available">drive-ata-smart-is-available</doc:ref>
is TRUE.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-is-failing" type="b" access="read">
+ <property name="drive-ata-smart-offline-data-collection-status" type="u" access="read">
<doc:doc><doc:description><doc:para>
- TRUE only if the drive is assessed to be failing.
+ Offline data collection status (TODO: specify values).
This property is only valid if
- <doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
is greater than zero.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-temperature" type="d" access="read">
+ <property name="drive-ata-smart-offline-data-collection-seconds" type="u" access="read">
<doc:doc><doc:description><doc:para>
- Temperature of the drive, in degrees celcius.
+ Number of seconds needed to perform offline data collection status.
This property is only valid if
- <doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
is greater than zero.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-time-powered-on" type="t" access="read">
+ <property name="drive-ata-smart-self-test-execution-status" type="u" access="read">
<doc:doc><doc:description><doc:para>
- Number of seconds the drive has been powered on.
+ Current status of self test (TODO: specify values).
This property is only valid if
- <doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
is greater than zero.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-last-self-test-result" type="s" access="read">
+ <property name="drive-ata-smart-self-test-execution-percent-remaining" type="u" access="read">
<doc:doc><doc:description><doc:para>
- The result of the last self-test. The following values are known:
- <doc:list>
- <doc:item>
- <doc:term>completed_ok</doc:term>
- <doc:definition>Completed without error or never run</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>not_completed_aborted</doc:term>
- <doc:definition>Aborted</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>not_completed_aborted_reset</doc:term>
- <doc:definition>Aborted by host</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>not_completed_unknown_reason</doc:term>
- <doc:definition>Aborted for unknown reason</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>completed_failed_unknown_reason</doc:term>
- <doc:definition>Completed, with failure:</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>completed_failed_electrical</doc:term>
- <doc:definition>Completed, with failure: electrical subsystem</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>completed_failed_servo</doc:term>
- <doc:definition>Completed, with failure: servo/seek subsystem</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>completed_failed_read</doc:term>
- <doc:definition>Completed, with failure: read failure</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>completed_failed_damage</doc:term>
- <doc:definition>Completed, with failure: handling damage</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>unknown</doc:term>
- <doc:definition>Unknown test result</doc:definition>
- </doc:item>
- </doc:list>
+ The progress of an ongoing self test or 0 if no self test is in progress.
This property is only valid if
- <doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
is greater than zero.
</doc:para></doc:description></doc:doc>
</property>
- <property name="drive-smart-attributes" type="a(isiiiis)" access="read">
+ <property name="drive-ata-smart-short-and-extended-self-test-available" type="b" access="read">
<doc:doc><doc:description><doc:para>
- An array of S.M.A.R.T. attributes. Each element contains the following members
- <doc:list>
- <doc:item>
- <doc:term>attribute id</doc:term>
- <doc:definition>the identifier of the attribute</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>attribute name</doc:term>
- <doc:definition>a human readable name of the attribute or blank</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>flags</doc:term>
- <doc:definition>Flags (TODO: link to spec)</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>value</doc:term>
- <doc:definition>The normalized value of the attribute</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>worst</doc:term>
- <doc:definition>The worst value seen</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>threshold</doc:term>
- <doc:definition>The threshold of the attribute</doc:definition>
- </doc:item>
- <doc:item>
- <doc:term>raw</doc:term>
- <doc:definition>The raw vendor specific value of the attribute</doc:definition>
- </doc:item>
- </doc:list>
+ Whether the short and extended self-tests are available.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-conveyance-self-test-available" type="b" access="read">
+ <doc:doc><doc:description><doc:para>
+ Whether the conveyance self-test is available.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-start-self-test-available" type="b" access="read">
+ <doc:doc><doc:description><doc:para>
+ Whether the start self-test is available.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-abort-self-test-available" type="b" access="read">
+ <doc:doc><doc:description><doc:para>
+ Whether the abort self-test is available.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+
+ <property name="drive-ata-smart-short-self-test-polling-minutes" type="u" access="read">
+ <doc:doc><doc:description><doc:para>
+ Recommended polling time in minutes for short self-test.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-extended-self-test-polling-minutes" type="u" access="read">
+ <doc:doc><doc:description><doc:para>
+ Recommended polling time in minutes for extended self-test.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-conveyance-self-test-polling-minutes" type="u" access="read">
+ <doc:doc><doc:description><doc:para>
+ Recommended polling time in minutes for conveyance self-test.
+ This property is only valid if
+ <doc:ref type="property" to="Device:drive-ata-smart-time-collected">drive-ata-smart-time-collected</doc:ref>
+ is greater than zero.
+ </doc:para></doc:description></doc:doc>
+ </property>
+ <property name="drive-ata-smart-attributes" type="a(usubbybybybbbutay)" access="read">
+ <doc:doc><doc:description><doc:para>
+ An array of ATA SMART attributes. Each element contains the following members (TODO).
This property is only valid if
<doc:ref type="property" to="Device:drive-smart-time-collected">drive-smart-time-collected</doc:ref>
is greater than zero.
</doc:para></doc:description></doc:doc>
</property>
+ <!-- **************************************************************************************************** -->
+
<property name="linux-md-component-level" type="s" access="read">
<doc:doc><doc:description><doc:para>
The RAID level of the array the component is part of. Known values include
g_print ("removed: %s\n", object_path);
}
-#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))
+#define ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_UINT, \
+ G_TYPE_STRING, \
+ G_TYPE_UINT, \
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \
+ G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+ G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+ G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \
+ G_TYPE_UINT, G_TYPE_UINT64, \
+ dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR), \
+ G_TYPE_INVALID))
+
+#define ATA_SMART_HISTORICAL_SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_UINT64, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_BOOLEAN, \
+ G_TYPE_DOUBLE, \
+ G_TYPE_UINT64, \
+ dbus_g_type_get_collection ("GPtrArray", ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE), \
+ G_TYPE_INVALID))
+
+#define LSOF_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_UINT, \
+ G_TYPE_UINT, \
+ G_TYPE_STRING, \
+ G_TYPE_INVALID))
+
/* --- SUCKY CODE BEGIN --- */
guint optical_disc_num_audio_tracks;
guint optical_disc_num_sessions;
- gboolean drive_smart_is_capable;
- gboolean drive_smart_is_enabled;
- guint64 drive_smart_time_collected;
- gboolean drive_smart_is_failing;
- double drive_smart_temperature;
- guint64 drive_smart_time_powered_on;
- char *drive_smart_last_self_test_result;
- GValue drive_smart_attributes;
+ gboolean drive_ata_smart_is_available;
+ gboolean drive_ata_smart_is_failing;
+ gboolean drive_ata_smart_is_failing_valid;
+ gboolean drive_ata_smart_has_bad_sectors;
+ gboolean drive_ata_smart_has_bad_attributes;
+ gdouble drive_ata_smart_temperature_kelvin;
+ guint64 drive_ata_smart_power_on_seconds;
+ guint64 drive_ata_smart_time_collected;
+ guint drive_ata_smart_offline_data_collection_status;
+ guint drive_ata_smart_offline_data_collection_seconds;
+ guint drive_ata_smart_self_test_execution_status;
+ guint drive_ata_smart_self_test_execution_percent_remaining;
+ gboolean drive_ata_smart_short_and_extended_self_test_available;
+ gboolean drive_ata_smart_conveyance_self_test_available;
+ gboolean drive_ata_smart_start_self_test_available;
+ gboolean drive_ata_smart_abort_self_test_available;
+ guint drive_ata_smart_short_self_test_polling_minutes;
+ guint drive_ata_smart_extended_self_test_polling_minutes;
+ guint drive_ata_smart_conveyance_self_test_polling_minutes;
+ GValue drive_ata_smart_attributes;
char *linux_md_component_level;
int linux_md_component_num_raid_devices;
else if (strcmp (key, "optical-disc-num-sessions") == 0)
props->optical_disc_num_sessions = g_value_get_uint (value);
- else if (strcmp (key, "drive-smart-is-capable") == 0)
- props->drive_smart_is_capable = g_value_get_boolean (value);
- else if (strcmp (key, "drive-smart-is-enabled") == 0)
- props->drive_smart_is_enabled = g_value_get_boolean (value);
- else if (strcmp (key, "drive-smart-time-collected") == 0)
- props->drive_smart_time_collected = g_value_get_uint64 (value);
- else if (strcmp (key, "drive-smart-is-failing") == 0)
- props->drive_smart_is_failing = g_value_get_boolean (value);
- else if (strcmp (key, "drive-smart-temperature") == 0)
- props->drive_smart_temperature = g_value_get_double (value);
- else if (strcmp (key, "drive-smart-time-powered-on") == 0)
- props->drive_smart_time_powered_on = g_value_get_uint64 (value);
- else if (strcmp (key, "drive-smart-last-self-test-result") == 0)
- props->drive_smart_last_self_test_result = g_strdup (g_value_get_string (value));
- else if (strcmp (key, "drive-smart-attributes") == 0) {
- g_value_copy (value, &(props->drive_smart_attributes));
+ else if (strcmp (key, "drive-ata-smart-is-available") == 0)
+ props->drive_ata_smart_is_available = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-is-failing") == 0)
+ props->drive_ata_smart_is_failing = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-is-failing-valid") == 0)
+ props->drive_ata_smart_is_failing_valid = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-has-bad-sectors") == 0)
+ props->drive_ata_smart_has_bad_sectors = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-has-bad-attributes") == 0)
+ props->drive_ata_smart_has_bad_attributes = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-temperature-kelvin") == 0)
+ props->drive_ata_smart_temperature_kelvin = g_value_get_double (value);
+ else if (strcmp (key, "drive-ata-smart-power-on-seconds") == 0)
+ props->drive_ata_smart_power_on_seconds = g_value_get_uint64 (value);
+ else if (strcmp (key, "drive-ata-smart-time-collected") == 0)
+ props->drive_ata_smart_time_collected = g_value_get_uint64 (value);
+ else if (strcmp (key, "drive-ata-smart-offline-data-collection-status") == 0)
+ props->drive_ata_smart_offline_data_collection_status = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-offline-data-collection-seconds") == 0)
+ props->drive_ata_smart_offline_data_collection_seconds = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-self-test-execution-status") == 0)
+ props->drive_ata_smart_self_test_execution_status = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-self-test-execution-percent-remaining") == 0)
+ props->drive_ata_smart_self_test_execution_percent_remaining = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-short-and-extended-self-test-available") == 0)
+ props->drive_ata_smart_short_and_extended_self_test_available = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-conveyance-self-test-available") == 0)
+ props->drive_ata_smart_conveyance_self_test_available = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-start-self-test-available") == 0)
+ props->drive_ata_smart_start_self_test_available = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-abort-self-test-available") == 0)
+ props->drive_ata_smart_abort_self_test_available = g_value_get_boolean (value);
+ else if (strcmp (key, "drive-ata-smart-short-self-test-polling-minutes") == 0)
+ props->drive_ata_smart_short_self_test_polling_minutes = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-extended-self-test-polling-minutes") == 0)
+ props->drive_ata_smart_extended_self_test_polling_minutes = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-conveyance-self-test-polling-minutes") == 0)
+ props->drive_ata_smart_conveyance_self_test_polling_minutes = g_value_get_uint (value);
+ else if (strcmp (key, "drive-ata-smart-attributes") == 0) {
+ g_value_copy (value, &(props->drive_ata_smart_attributes));
}
else if (strcmp (key, "linux-md-component-level") == 0)
g_free (props->drive_connection_interface);
g_strfreev (props->drive_media_compatibility);
g_free (props->drive_media);
- g_free (props->drive_smart_last_self_test_result);
- g_value_unset (&(props->drive_smart_attributes));
+
+ g_value_unset (&(props->drive_ata_smart_attributes));
+
g_free (props->linux_md_component_level);
g_free (props->linux_md_component_uuid);
g_free (props->linux_md_component_home_host);
const char *ifname = "org.freedesktop.DeviceKit.Disks.Device";
props = g_new0 (DeviceProperties, 1);
- g_value_init (&(props->drive_smart_attributes),
- dbus_g_type_get_collection ("GPtrArray", SMART_DATA_STRUCT_TYPE));
+ g_value_init (&(props->drive_ata_smart_attributes),
+ dbus_g_type_get_collection ("GPtrArray", ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE));
prop_proxy = dbus_g_proxy_new_for_name (bus,
"org.freedesktop.DeviceKit.Disks",
return FALSE;
}
+static const gchar *
+print_available (gboolean available)
+{
+ if (available)
+ return "available";
+ else
+ return "not available";
+}
+
+static const gchar *
+get_ata_smart_offline_status (guint offline_status)
+{
+ const gchar *ret;
+
+ switch (offline_status) {
+ case 0: ret = "never collected"; break;
+ case 1: ret = "successful"; break;
+ case 2: ret = "in progress"; break;
+ case 3: ret = "suspended"; break;
+ case 4: ret = "aborted"; break;
+ case 5: ret = "fatal"; break;
+ default: ret = "unknown"; break;
+ }
+
+ return ret;
+}
+
+static const gchar *
+get_ata_smart_self_test_status (guint self_test_status)
+{
+ const gchar *ret;
+
+ switch (self_test_status) {
+ case 0: ret = "success or never"; break;
+ case 1: ret = "aborted"; break;
+ case 2: ret = "interrupted"; break;
+ case 3: ret = "fatal"; break;
+ case 4: ret = "error (unknown)"; break;
+ case 5: ret = "error (electrical)"; break;
+ case 6: ret = "error (servo)"; break;
+ case 7: ret = "error (read)"; break;
+ case 8: ret = "error (handling)"; break;
+ case 15: ret = "in progress"; break;
+ default: ret = "unknown"; break;
+ }
+
+ return ret;
+}
+
+static gchar *
+get_ata_smart_unit (guint unit, guint64 pretty_value)
+{
+ gchar *ret;
+
+ switch (unit) {
+ default:
+ case 0:
+ case 1:
+ ret = g_strdup_printf ("%" G_GUINT64_FORMAT, pretty_value);
+ break;
+
+ case 2:
+ if (pretty_value > 1000 * 60 * 60 * 24) {
+ ret = g_strdup_printf ("%.3g days", pretty_value / 1000.0 / 60.0 / 60.0 / 24.0);
+ } else if (pretty_value > 1000 * 60 * 60) {
+ ret = g_strdup_printf ("%.3g hours", pretty_value / 1000.0 / 60.0 / 60.0);
+ } else if (pretty_value > 1000 * 60) {
+ ret = g_strdup_printf ("%.3g mins", pretty_value / 1000.0 / 60.0);
+ } else if (pretty_value > 1000) {
+ ret = g_strdup_printf ("%.3g secs", pretty_value / 1000.0);
+ } else {
+ ret = g_strdup_printf ("%d msec", (gint) pretty_value);
+ }
+ break;
+
+ case 3:
+ ret = g_strdup_printf ("%" G_GUINT64_FORMAT " sectors", pretty_value);
+ break;
+
+ case 4:
+ ret = g_strdup_printf ("%.3gC / %.3gF",
+ pretty_value / 1000.0 - 273.15,
+ (pretty_value / 1000.0 - 273.15) * 9.0 / 5.0 + 32.0);
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+has_colors (void)
+{
+ static gboolean ret = FALSE;
+ static gboolean checked = FALSE;
+
+ if (checked)
+ return ret;
+
+ if (isatty (STDOUT_FILENO)) {
+ ret = TRUE;
+ }
+
+ checked = TRUE;
+
+ return ret;
+}
+
+static void
+begin_highlight (void)
+{
+ if (has_colors ())
+ g_print ("\x1B[1;31m");
+}
+
+static void
+end_highlight (void)
+{
+ if (has_colors ())
+ g_print ("\x1B[0m");
+}
+
static void
do_show_info (const char *object_path)
{
else
g_print (" if speed: %" G_GINT64_FORMAT " bits/s\n", props->drive_connection_speed);
- if (!props->drive_smart_is_capable) {
- g_print (" S.M.A.R.T.: not capable\n");
- } else if (props->drive_smart_time_collected == 0) {
- g_print (" S.M.A.R.T.: not collected\n");
+ /* ------------------------------------------------------------------------------------------------- */
+
+ if (!props->drive_ata_smart_is_available) {
+ g_print (" ATA SMART: not available\n");
+ } else if (props->drive_ata_smart_time_collected == 0) {
+ g_print (" ATA SMART: Data not collected\n");
} else {
struct tm *time_tm;
time_t time;
char time_buf[256];
+ GPtrArray *p;
- time = (time_t) props->drive_smart_time_collected;
+ time = (time_t) props->drive_ata_smart_time_collected;
time_tm = localtime (&time);
strftime (time_buf, sizeof time_buf, "%c", time_tm);
- g_print (" S.M.A.R.T.: Information collected at %s\n", time_buf);
- if (!props->drive_smart_is_capable) {
- g_print (" not capable\n");
- } else if (!props->drive_smart_is_enabled) {
- g_print (" not enabled\n");
+
+ g_print (" ATA SMART: Updated at %s\n", time_buf);
+ if (props->drive_ata_smart_is_failing_valid) {
+ if (!props->drive_ata_smart_is_failing)
+ g_print (" assessment: PASSED\n");
+ else {
+ g_print (" assessment: ");
+ begin_highlight ();
+ g_print ("FAILING");
+ end_highlight ();
+ g_print ("\n");
+ }
+
+ } else {
+ g_print (" assessment: Unknown\n");
+ }
+
+ if (props->drive_ata_smart_has_bad_sectors) {
+ begin_highlight ();
+ g_print (" bad sectors: Yes\n");
+ end_highlight ();
+ } else {
+ g_print (" bad sectors: None\n");
+ }
+
+ if (props->drive_ata_smart_has_bad_attributes) {
+ begin_highlight ();
+ g_print (" attributes: One ore more attrinbutes exceeds threshold\n");
+ end_highlight ();
+ } else {
+ g_print (" attributes: Within threshold\n");
+ }
+
+ if (props->drive_ata_smart_temperature_kelvin < 0.1) {
+ g_print (" temperature: Unknown\n");
+ } else {
+ gdouble celcius;
+ gdouble fahrenheit;
+ celcius = props->drive_ata_smart_temperature_kelvin - 273.15;
+ fahrenheit = 9.0 * celcius / 5.0 + 32.0;
+ g_print (" temperature: %.3g\302\260 C / %.3g\302\260 F\n", celcius, fahrenheit);
+ }
+
+ if (props->drive_ata_smart_power_on_seconds == 0) {
+ g_print (" power on hours: Unknown\n");
+ g_print (" powered on: Unknown\n");
} else {
+ gchar *power_on_text;
+ guint val;
- g_print (" assessment: %s\n",
- props->drive_smart_is_failing ? "FAILING" : "Passed");
- g_print (" temperature: %g\302\260 C / %g\302\260 F\n",
- props->drive_smart_temperature,
- 9 * props->drive_smart_temperature / 5 + 32);
- g_print (" powered on: %" G_GUINT64_FORMAT " hours\n", props->drive_smart_time_powered_on / 3600);
- //g_print (" 196 Reallocated_Event_Count 0x0032 100 100 0 443023360\n",
- g_print (" =========================================================================\n");
- g_print (" Id Description Flags Value Worst Threshold Raw\n");
- g_print (" =========================================================================\n");
- GPtrArray *p;
- p = g_value_get_boxed (&(props->drive_smart_attributes));
- for (m = 0; m < p->len; m++) {
- gint attr_id;
- gchar *attr_desc;
- gint attr_flags;
- gint attr_value;
- gint attr_worst;
- gint attr_threshold;
- gchar *attr_raw;
- GValue elem = {0};
-
- g_value_init (&elem, SMART_DATA_STRUCT_TYPE);
- g_value_set_static_boxed (&elem, p->pdata[m]);
-
- dbus_g_type_struct_get (&elem,
- 0, &(attr_id),
- 1, &(attr_desc),
- 2, &(attr_flags),
- 3, &(attr_value),
- 4, &(attr_worst),
- 5, &(attr_threshold),
- 6, &(attr_raw),
- G_MAXUINT);
-
- g_print (" %3d %-28s 0x%04x %5d %5d %9d %s\n",
- attr_id,
- attr_desc,
- attr_flags,
- attr_value,
- attr_worst,
- attr_threshold,
- attr_raw);
-
- g_free (attr_desc);
- g_free (attr_raw);
-
- g_value_unset (&elem);
+ val = props->drive_ata_smart_power_on_seconds;
+
+ if (val > 60 * 60 * 24) {
+ power_on_text = g_strdup_printf (_("%.3g days"), val / 60.0 / 60.0 / 24.0);
+ } else {
+ power_on_text = g_strdup_printf (_("%.3g hours"), val / 60.0 / 60.0);
}
+
+ g_print (" powered on: %s\n", power_on_text);
+ g_free (power_on_text);
+ }
+
+
+ g_print (" offline data: %s (%d second(s) to complete)\n", get_ata_smart_offline_status (props->drive_ata_smart_offline_data_collection_status), props->drive_ata_smart_offline_data_collection_seconds);
+ g_print (" self-test status: %s (%d%% remaining)\n", get_ata_smart_self_test_status (props->drive_ata_smart_self_test_execution_status), props->drive_ata_smart_self_test_execution_percent_remaining);
+ g_print (" ext./short test: %s\n", print_available (props->drive_ata_smart_short_and_extended_self_test_available));
+ g_print (" conveyance test: %s\n", print_available (props->drive_ata_smart_conveyance_self_test_available));
+ g_print (" start test: %s\n", print_available (props->drive_ata_smart_start_self_test_available));
+ g_print (" abort test: %s\n", print_available (props->drive_ata_smart_abort_self_test_available));
+ g_print (" short test: %3d minute(s) recommended polling time\n", props->drive_ata_smart_short_self_test_polling_minutes);
+ g_print (" ext. test: %3d minute(s) recommended polling time\n", props->drive_ata_smart_extended_self_test_polling_minutes);
+ g_print (" conveyance test: %3d minute(s) recommended polling time\n", props->drive_ata_smart_conveyance_self_test_polling_minutes);
+ g_print ("===============================================================================\n");
+ g_print (" Attribute Current/Worst/Threshold Status Value Type Updates\n");
+ g_print ("===============================================================================\n");
+ p = g_value_get_boxed (&(props->drive_ata_smart_attributes));
+ for (m = 0; m < p->len; m++) {
+ GValue elem = {0};
+ guint id;
+ gchar *name;
+ guint flags;
+ gboolean online, prefailure;
+ guchar current;
+ gboolean current_valid;
+ guchar worst;
+ gboolean worst_valid;
+ guchar threshold;
+ gboolean threshold_valid;
+ gboolean good, good_valid;
+ guint pretty_unit;
+ guint64 pretty_value;
+ gchar *pretty;
+ const gchar *assessment;
+ const gchar *type;
+ const gchar *updates;
+ gboolean do_highlight;
+ GArray *raw_data;
+
+ g_value_init (&elem, ATA_SMART_DATA_ATTRIBUTE_STRUCT_TYPE);
+ g_value_set_static_boxed (&elem, p->pdata[m]);
+
+ dbus_g_type_struct_get (&elem,
+ 0, &id,
+ 1, &name,
+ 2, &flags,
+ 3, &online,
+ 4, &prefailure,
+ 5, ¤t,
+ 6, ¤t_valid,
+ 7, &worst,
+ 8, &worst_valid,
+ 9, &threshold,
+ 10, &threshold_valid,
+ 11, &good,
+ 12, &good_valid,
+ 13, &pretty_unit,
+ 14, &pretty_value,
+ 15, &raw_data,
+ G_MAXUINT);
+
+ pretty = get_ata_smart_unit (pretty_unit, pretty_value);
+
+ do_highlight = FALSE;
+ if (!good_valid)
+ assessment = " n/a";
+ else if (good)
+ assessment = "good";
+ else {
+ assessment = "FAIL";
+ do_highlight = TRUE;
+ }
+
+ if (online)
+ updates = "Online ";
+ else
+ updates = "Offline";
+
+ if (prefailure)
+ type = "Prefail";
+ else
+ type = "Old-age";
+
+ if (do_highlight)
+ begin_highlight ();
+
+ g_print (" %-27s %3d/%3d/%3d %s %-11s %s %s\n",
+ name,
+ current,
+ worst,
+ threshold,
+ assessment,
+ pretty,
+ type,
+ updates);
+
+ if (do_highlight)
+ end_highlight ();
+
+
+ g_free (pretty);
+
+ g_array_free (raw_data, TRUE);
+ g_value_unset (&elem);
}
}
+ /* ------------------------------------------------------------------------------------------------- */
+
+
}
device_properties_free (props);
}
{ NULL }
};
- ret = 1;
-
setlocale (LC_ALL, "");
+ ret = 1;
+
g_type_init ();
context = g_option_context_new ("DeviceKit-disks tool");