[gnome-disk-utility/udisks2-port] Add SMART functionality
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/udisks2-port] Add SMART functionality
- Date: Fri, 2 Sep 2011 20:08:04 +0000 (UTC)
commit 9218e1f98dfed532dec91e63370d6cad304339e9
Author: David Zeuthen <davidz redhat com>
Date: Fri Sep 2 16:07:59 2011 -0400
Add SMART functionality
Signed-off-by: David Zeuthen <davidz redhat com>
data/ui/palimpsest.ui | 15 +-
src/palimpsest/Makefile.am | 1 +
src/palimpsest/gduatasmartdialog.c | 1524 ++++++++++++++++++++++++++++++++++++
src/palimpsest/gduatasmartdialog.h | 40 +
src/palimpsest/gduwindow.c | 138 ++--
src/palimpsest/gduwindow.h | 4 +
6 files changed, 1631 insertions(+), 91 deletions(-)
---
diff --git a/data/ui/palimpsest.ui b/data/ui/palimpsest.ui
index f2c6e68..e7e0118 100644
--- a/data/ui/palimpsest.ui
+++ b/data/ui/palimpsest.ui
@@ -61,6 +61,15 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
+ <object class="GtkMenuItem" id="generic-menu-item-view-smart">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">View SMART data...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
<object class="GtkMenuItem" id="generic-menu-item-configure-fstab">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -308,7 +317,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
- <property name="label" translatable="yes">Serial</property>
+ <property name="label" translatable="yes">Serial Number</property>
<attributes>
<attribute name="foreground" value="#555555555555"/>
</attributes>
@@ -395,7 +404,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
- <property name="label" translatable="yes">Size</property>
+ <property name="label" translatable="yes">Disk Size</property>
<attributes>
<attribute name="foreground" value="#555555555555"/>
</attributes>
@@ -432,7 +441,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
- <property name="label" translatable="yes">Status</property>
+ <property name="label" translatable="yes">Assessment</property>
<attributes>
<attribute name="foreground" value="#555555555555"/>
</attributes>
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index 9019a68..7b9cdc0 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -31,6 +31,7 @@ palimpsest_SOURCES = \
gduutils.h gduutils.c \
gduvolumegrid.h gduvolumegrid.c \
gduwindow.h gduwindow.c \
+ gduatasmartdialog.h gduatasmartdialog.c \
$(enum_built_sources) \
$(NULL)
diff --git a/src/palimpsest/gduatasmartdialog.c b/src/palimpsest/gduatasmartdialog.c
new file mode 100644
index 0000000..3b654e2
--- /dev/null
+++ b/src/palimpsest/gduatasmartdialog.c
@@ -0,0 +1,1524 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gduapplication.h"
+#include "gduwindow.h"
+#include "gduatasmartdialog.h"
+
+typedef struct
+{
+ UDisksObject *object;
+ UDisksDriveAta *ata;
+
+ GduWindow *window;
+ GtkBuilder *builder;
+
+ GtkListStore *attributes_list;
+
+ GtkWidget *dialog;
+ GtkWidget *updated_label;
+ GtkWidget *temperature_label;
+ GtkWidget *powered_on_label;
+ GtkWidget *self_test_label;
+ GtkWidget *self_assessment_label;
+ GtkWidget *overall_assessment_label;
+
+ GtkWidget *attributes_treeview;
+
+ GtkWidget *start_selftest_button;
+ GtkWidget *stop_selftest_button;
+
+ GtkWidget *selftest_menu;
+ GtkWidget *selftest_short_menuitem;
+ GtkWidget *selftest_extended_menuitem;
+ GtkWidget *selftest_conveyance_menuitem;
+} DialogData;
+
+static const struct {
+ goffset offset;
+ const gchar *name;
+} widget_mapping[] = {
+ {G_STRUCT_OFFSET (DialogData, updated_label), "updated-label"},
+ {G_STRUCT_OFFSET (DialogData, temperature_label), "temperature-label"},
+ {G_STRUCT_OFFSET (DialogData, powered_on_label), "powered-on-label"},
+ {G_STRUCT_OFFSET (DialogData, self_test_label), "self-test-label"},
+ {G_STRUCT_OFFSET (DialogData, self_assessment_label), "self-assessment-label"},
+ {G_STRUCT_OFFSET (DialogData, overall_assessment_label), "overall-assessment-label"},
+ {G_STRUCT_OFFSET (DialogData, attributes_treeview), "attributes-treeview"},
+ {G_STRUCT_OFFSET (DialogData, selftest_menu), "selftest-menu"},
+ {G_STRUCT_OFFSET (DialogData, selftest_short_menuitem), "selftest-short-menuitem"},
+ {G_STRUCT_OFFSET (DialogData, selftest_extended_menuitem), "selftest-extended-menuitem"},
+ {G_STRUCT_OFFSET (DialogData, selftest_conveyance_menuitem), "selftest-conveyance-menuitem"},
+ {0, NULL}
+};
+
+static void
+dialog_data_free (DialogData *data)
+{
+ if (data->dialog != NULL)
+ {
+ gtk_widget_hide (data->dialog);
+ gtk_widget_destroy (data->dialog);
+ }
+ if (data->object != NULL)
+ g_object_unref (data->object);
+ if (data->window != NULL)
+ g_object_unref (data->window);
+ if (data->builder != NULL)
+ g_object_unref (data->builder);
+
+ if (data->attributes_list != NULL)
+ g_object_unref (data->attributes_list);
+
+ g_free (data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+
+static gchar *
+age_to_string (guint age_seconds)
+{
+ gchar *s;
+
+ if (age_seconds < 60)
+ {
+ s = g_strdup_printf (_("Less than a minute ago"));
+ //next_update = 60 - age_seconds;
+ }
+ else if (age_seconds < 60 * 60)
+ {
+ s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ N_("%d minute ago"),
+ N_("%d minutes ago"),
+ age_seconds / 60),
+ age_seconds / 60);
+ //next_update = 60*(age_seconds/60 + 1) - age_seconds;
+ }
+ else
+ {
+ s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ N_("%d hour ago"),
+ N_("%d hours ago"),
+ age_seconds / 60 / 60),
+ age_seconds / 60 / 60);
+ //next_update = 60*60*(age_seconds/(60*60) + 1) - age_seconds;
+ }
+ return s;
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+ const gchar *name;
+ const gchar *pretty_name;
+ const gchar *desc;
+} SmartDetails;
+
+/* See http://smartmontools.sourceforge.net/doc.html
+ * http://en.wikipedia.org/wiki/S.M.A.R.T
+ * http://www.t13.org/Documents/UploadedDocuments/docs2005/e05148r0-ACS-ATA_SMARTAttributesAnnex.pdf
+ *
+ * Keep in sync with libatasmart. Last sync: Thu Aug 20 2009
+ */
+static const SmartDetails smart_details[] = {
+{
+ "raw-read-error-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Read Error Rate"),
+ N_("Frequency of errors while reading raw data from the disk. "
+ "A non-zero value indicates a problem with "
+ "either the disk surface or read/write heads")
+},
+{
+ "throughput-performance",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Throughput Performance"),
+ N_("Average efficiency of the disk")
+},
+{
+ "spin-up-time",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spinup Time"),
+ N_("Time needed to spin up the disk")
+},
+{
+ "start-stop-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Start/Stop Count"),
+ N_("Number of spindle start/stop cycles")
+},
+{
+ "reallocated-sector-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Reallocated Sector Count"),
+ N_("Count of remapped sectors. "
+ "When the hard drive finds a read/write/verification error, it marks the sector "
+ "as \"reallocated\" and transfers data to a special reserved area (spare area)")
+},
+{
+ "read-channel-margin",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Read Channel Margin"),
+ N_("Margin of a channel while reading data.")
+},
+{
+ "seek-error-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Seek Error Rate"),
+ N_("Frequency of errors while positioning")
+},
+{
+ "seek-time-performance",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Seek Timer Performance"),
+ N_("Average efficiency of operations while positioning")
+},
+{
+ "power-on-hours",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-On Hours"),
+ N_("Number of hours elapsed in the power-on state")
+},
+{
+ "spin-retry-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spinup Retry Count"),
+ N_("Number of retry attempts to spin up")
+},
+{
+ "calibration-retry-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Calibration Retry Count"),
+ N_("Number of attempts to calibrate the device")
+},
+{
+ "power-cycle-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power Cycle Count"),
+ N_("Number of power-on events")
+},
+{
+ "read-soft-error-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Soft read error rate"),
+ N_("Frequency of 'program' errors while reading from the disk")
+},
+{
+ "reported-uncorrect",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Reported Uncorrectable Errors"),
+ N_("Number of errors that could not be recovered using hardware ECC")
+},
+{
+ "high-fly-writes",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("High Fly Writes"),
+ N_("Number of times a recording head is flying outside its normal operating range")
+},
+{
+ "airflow-temperature-celsius",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Airflow Temperature"),
+ N_("Airflow temperature of the drive")
+},
+{
+ "g-sense-error-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("G-sense Error Rate"),
+ N_("Frequency of mistakes as a result of impact loads")
+},
+{
+ "power-off-retract-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-off Retract Count"),
+ N_("Number of power-off or emergency retract cycles")
+},
+{
+ "load-cycle-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load/Unload Cycle Count"),
+ N_("Number of cycles into landing zone position")
+},
+{
+ "temperature-celsius-2",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Temperature"),
+ N_("Current internal temperature of the drive")
+},
+{
+ "hardware-ecc-recovered",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Hardware ECC Recovered"),
+ N_("Number of ECC on-the-fly errors")
+},
+{
+ "reallocated-event-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Reallocation Count"),
+ N_("Number of remapping operations. "
+ "The raw value of this attribute shows the total number of (successful "
+ "and unsuccessful) attempts to transfer data from reallocated sectors "
+ "to a spare area")
+},
+{
+ "current-pending-sector",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Current Pending Sector Count"),
+ N_("Number of sectors waiting to be remapped. "
+ "If the sector waiting to be remapped is subsequently written or read "
+ "successfully, this value is decreased and the sector is not remapped. Read "
+ "errors on the sector will not remap the sector, it will only be remapped on "
+ "a failed write attempt")
+},
+{
+ "offline-uncorrectable",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Uncorrectable Sector Count"),
+ N_("The total number of uncorrectable errors when reading/writing a sector. "
+ "A rise in the value of this attribute indicates defects of the "
+ "disk surface and/or problems in the mechanical subsystem")
+},
+{
+ "udma-crc-error-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("UDMA CRC Error Rate"),
+ N_("Number of CRC errors during UDMA mode")
+},
+{
+ "multi-zone-error-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Write Error Rate"),
+ N_("Number of errors while writing to disk (or) multi-zone error rate (or) flying-height")
+},
+{
+ "soft-read-error-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Soft Read Error Rate"),
+ N_("Number of off-track errors")
+},
+{
+ "ta-increase-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Data Address Mark Errors"),
+ N_("Number of Data Address Mark (DAM) errors (or) vendor-specific")
+},
+{
+ "run-out-cancel",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Run Out Cancel"),
+ N_("Number of ECC errors")
+},
+{
+ "shock-count-write-open",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Soft ECC correction"),
+ N_("Number of errors corrected by software ECC")
+},
+{
+ "shock-rate-write-open",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Thermal Asperity Rate"),
+ N_("Number of Thermal Asperity Rate errors")
+},
+{
+ "flying-height",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Flying Height"),
+ N_("Height of heads above the disk surface")
+},
+{
+ "spin-high-current",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spin High Current"),
+ N_("Amount of high current used to spin up the drive")
+},
+{
+ "spin-buzz",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spin Buzz"),
+ N_("Number of buzz routines to spin up the drive")
+},
+{
+ "offline-seek-performance",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Offline Seek Performance"),
+ N_("Drive's seek performance during offline operations")
+},
+{
+ "disk-shift",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Disk Shift"),
+ N_("Shift of disk is possible as a result of strong shock loading in the store, "
+ "as a result of falling (or) temperature")
+},
+{
+ "g-sense-error-rate-2",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("G-sense Error Rate"),
+ N_("Number of errors as a result of impact loads as detected by a shock sensor")
+},
+{
+ "loaded-hours",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Loaded Hours"),
+ N_("Number of hours in general operational state")
+},
+{
+ "load-retry-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load/Unload Retry Count"),
+ N_("Loading on drive caused by numerous recurrences of operations, like reading, "
+ "recording, positioning of heads, etc")
+},
+{
+ "load-friction",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load Friction"),
+ N_("Load on drive caused by friction in mechanical parts of the store")
+},
+{
+ "load-cycle-count-2",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load/Unload Cycle Count"),
+ N_("Total number of load cycles")
+},
+{
+ "load-in-time",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load-in Time"),
+ N_("General time for loading in a drive")
+},
+{
+ "torq-amp-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Torque Amplification Count"),
+ N_("Quantity efforts of the rotating moment of a drive")
+},
+{
+ "power-off-retract-count-2",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-off Retract Count"),
+ N_("Number of power-off retract events")
+},
+{
+ "head-amplitude",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("GMR Head Amplitude"),
+ N_("Amplitude of heads trembling (GMR-head) in running mode")
+},
+{
+ "temperature-celsius",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Temperature"),
+ N_("Temperature of the drive")
+},
+{
+ "endurance-remaining",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Endurance Remaining"),
+ N_("Number of physical erase cycles completed on the drive as "
+ "a percentage of the maximum physical erase cycles the drive supports")
+},
+{
+ "power-on-seconds-2",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-On Hours"),
+ N_("Number of hours elapsed in the power-on state")
+},
+{
+ "uncorrectable-ecc-count",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Uncorrectable ECC Count"),
+ N_("Number of uncorrectable ECC errors")
+},
+{
+ "good-block-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Good Block Rate"),
+ N_("Number of available reserved blocks as a percentage "
+ "of the total number of reserved blocks"),
+},
+{
+ "head-flying-hours",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Head Flying Hours"),
+ N_("Time while head is positioning")
+},
+{
+ "read-error-retry-rate",
+ /* Translators: SMART attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Read Error Retry Rate"),
+ N_("Number of errors while reading from a disk")
+},
+{
+ NULL,
+ NULL,
+ NULL
+}
+};
+
+/* TODO: move to libudisks2 */
+static gboolean
+attribute_get_details (const gchar *name,
+ const gchar **out_name,
+ const gchar **out_description)
+{
+ SmartDetails *details;
+ static volatile gsize have_hash = 0;
+ static GHashTable *smart_details_map = NULL;
+ gboolean ret;
+
+ if (g_once_init_enter (&have_hash))
+ {
+ guint n;
+ smart_details_map = g_hash_table_new (g_str_hash, g_str_equal);
+ for (n = 0; smart_details[n].name != NULL; n++)
+ {
+ g_hash_table_insert (smart_details_map,
+ (gpointer) smart_details[n].name,
+ (gpointer) &(smart_details[n]));
+ }
+ g_once_init_leave (&have_hash, 1);
+ }
+
+ ret = FALSE;
+
+ details = g_hash_table_lookup (smart_details_map, name);
+ if (details != NULL)
+ {
+ if (out_name != NULL)
+ *out_name = gettext (details->pretty_name);
+ if (out_description != NULL)
+ *out_description = gettext (details->desc);;
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+attr_format_desc (gint id, const gchar *name)
+{
+ const gchar *localized_name;
+ const gchar *localized_desc;
+ const gchar *n;
+ gchar *ret;
+
+ if (attribute_get_details (name, &localized_name, &localized_desc))
+ n = localized_name;
+ else
+ n = name;
+
+ ret = g_strdup_printf ("<b>%s</b>", n);
+
+ return ret;
+}
+
+static gchar *
+attr_format_assessment (gint current,
+ gint worst,
+ gint threshold,
+ guint16 flags)
+{
+ gchar *ret;
+ gboolean failed = FALSE;
+ gboolean failed_in_the_past = FALSE;
+
+ if (current > 0 && threshold > 0 && current <= threshold)
+ failed = TRUE;
+
+ if (worst > 0 && threshold > 0 && worst <= threshold)
+ failed_in_the_past = TRUE;
+
+ if (failed)
+ {
+ ret = g_strdup_printf ("<span foreground=\"#ff0000\"><b>%s</b></span>",
+ /* Translators: Shown in the treeview for a failing attribute */
+ _("FAILING"));
+ }
+ else if (failed_in_the_past)
+ {
+ ret = g_strdup_printf ("<span foreground=\"#ff0000\">%s</span>",
+ /* Translators: Shown in the treeview for an attribute that failed in the past */
+ _("Failed in the past"));
+ }
+ else
+ {
+ ret = g_strdup (_("OK"));
+ }
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+format_duration_msec (guint64 msec)
+{
+ gchar *ret;
+ if (msec > 1000 * 60 * 60 * 24 * 365.25)
+ {
+ /* Translators: Used for a time-based unit that exceed one year */
+ ret = g_strdup_printf (_("%.1f years"), msec / 1000.0 / 60.0 / 60.0 / 24.0 / 365.25);
+ }
+ else if (msec > 1000 * 60 * 60 * 24)
+ {
+ /* Translators: Used for a time-based unit that exceed one day but not one year */
+ ret = g_strdup_printf (_("%.1f days"), msec / 1000.0 / 60.0 / 60.0 / 24.0);
+ }
+ else if (msec > 1000 * 60 * 60)
+ {
+ /* Translators: Used for a time-based unit that exceed one hour but not one day */
+ ret = g_strdup_printf (_("%.1f hours"), msec / 1000.0 / 60.0 / 60.0);
+ }
+ else if (msec > 1000 * 60)
+ {
+ /* Translators: Used for a time-based unit that exceed one minute but not one hour */
+ ret = g_strdup_printf (_("%.1f minutes"), msec / 1000.0 / 60.0);
+ }
+ else if (msec > 1000)
+ {
+ /* Translators: Used for a time-based unit that exceed one second but not one minute */
+ ret = g_strdup_printf (_("%.1f seconds"), msec / 1000.0);
+ }
+ else
+ {
+ /* Translators: Used for a time-based unit that is counted in milliseconds and doesn't exceed one second */
+ ret = g_strdup_printf (_("%d msec"), (gint) msec);
+ }
+ return ret;
+}
+
+static gchar *
+pretty_to_string (guint64 pretty,
+ gint pretty_unit)
+{
+ gchar *ret;
+ gdouble celcius;
+ gdouble fahrenheit;
+
+ switch (pretty_unit)
+ {
+ case 2: /* SK_SMART_ATTRIBUTE_UNIT_MSECONDS */
+ ret = format_duration_msec (pretty);
+ break;
+
+ case 3: /* SK_SMART_ATTRIBUTE_UNIT_SECTORS */
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a sector-based unit */
+ ret = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "%d sector",
+ "%d sectors",
+ (gint) pretty),
+ (gint) pretty);
+ break;
+
+ case 4: /* SK_SMART_ATTRIBUTE_UNIT_MKELVIN */
+ celcius = pretty / 1000.0 - 273.15;
+ fahrenheit = 9.0 * celcius / 5.0 + 32.0;
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a temperature-based unit - first %f is the temperature in degrees Celcius, second %f
+ * is the temperature in degrees Fahrenheit */
+ ret = g_strdup_printf (_("%.0f C / %.0f F"), celcius, fahrenheit);
+ break;
+
+ case 1: /* SK_SMART_ATTRIBUTE_UNIT_NONE */
+ ret = g_strdup_printf ("%" G_GUINT64_FORMAT, pretty);
+ break;
+
+ default:
+ case 0: /* SK_SMART_ATTRIBUTE_UNIT_UNKNOWN */
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * where the value cannot be interpreted */
+ ret = g_strdup (_("N/A"));
+ break;
+ }
+
+ return ret;
+}
+
+
+static gchar *
+attr_format_value (gint current,
+ gint worst,
+ gint threshold,
+ guint64 pretty,
+ gint pretty_unit,
+ gchar **out_value2)
+{
+ gchar *ret;
+ gchar *current_str;
+ gchar *worst_str;
+ gchar *threshold_str;
+ gchar *pretty_str;
+
+ if (current >= 0)
+ current_str = g_strdup_printf ("%d", current);
+ else
+ current_str = g_strdup ("â");
+
+ if (worst >= 0)
+ worst_str = g_strdup_printf ("%d", worst);
+ else
+ worst_str = g_strdup ("â");
+
+ if (threshold >= 0)
+ threshold_str = g_strdup_printf ("%d", threshold);
+ else
+ threshold_str = g_strdup ("â");
+
+ pretty_str = pretty_to_string (pretty, pretty_unit);
+
+ ret = g_strdup_printf ("<small>"
+ "%s: %s\n"
+ "%s: %s"
+ "</small>",
+ /* Translators: Shown in the tree view for the normalized value of an attribute (0-254) */
+ _("Normalized"), current_str,
+ /* Translators: Shown in the tree view for the worst value of an attribute (0-254) */
+ _("Worst"), worst_str);
+
+ *out_value2 = g_strdup_printf ("<small>"
+ "%s: %s\n"
+ "%s: %s"
+ "</small>",
+ /* Translators: Shown in the tree view for the threshold of an attribute (0-254) */
+ _("Threshold"), threshold_str,
+ /* Translators: Shown in the tree view for the interpreted/pretty value of an attribute */
+ _("Value"), pretty_str);
+ g_free (current_str);
+ g_free (worst_str);
+ g_free (threshold_str);
+ g_free (pretty_str);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+attr_format_tooltip (gint id,
+ const gchar *name,
+ guint16 flags)
+{
+ gboolean prefail;
+ gboolean online;
+ const gchar *type_str;
+ const gchar *updates_str;
+ gchar *ret;
+ const gchar *localized_name;
+ const gchar *localized_desc;
+ gchar *n;
+ gchar *d;
+
+ if (attribute_get_details (name, &localized_name, &localized_desc))
+ {
+ n = g_strdup (localized_name);
+ d = g_strdup (localized_desc);
+ }
+ else
+ {
+ n = g_strdup (name);
+ d = g_strdup_printf (_("No description for attribute %d"), id);
+ }
+
+ prefail = (flags & 0x0001);
+ online = (flags & 0x0002);
+
+ if (prefail)
+ {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Pre-Fail)" in English
+ */
+ type_str = _("Failure is a sign the disk will fail within 24 hours (Pre-Fail)");
+ }
+ else
+ {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Old-Age)" in English
+ */
+ type_str = _("Failure is a sign the disk exceeded its intended design life period (Old-Age)");
+ }
+
+ if (online)
+ {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Online)" in English
+ */
+ updates_str = _("Every time data is collected (Online)");
+ }
+ else
+ {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Not Online)" in English
+ */
+ updates_str = _("Only during off-line activities (Not Online)");
+ }
+
+ ret = g_strdup_printf ("<b>%s</b>: %s\n\n"
+ "<b>%s</b>: %s\n\n"
+ "<b>%s</b>: %s\n\n"
+ "<b>%s</b>: %s",
+ /* Translators: Used in the tooltip for a SMART attribute */
+ _("Name"), n,
+ /* Translators: Used in the tooltip for a SMART attribute */
+ _("Type"), type_str,
+ /* Translators: Used in the tooltip for a SMART attribute */
+ _("Updates"), updates_str,
+ /* Translators: Used in the tooltip for a SMART attribute */
+ _("Description"), d);
+
+ g_free (n);
+ g_free (d);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+calculate_self_test (DialogData *data,
+ gboolean *out_selftest_running)
+{
+ const gchar *s;
+ gchar *ret;
+ gboolean selftest_running = FALSE;
+
+ s = udisks_drive_ata_get_smart_selftest_status (data->ata);
+ if (g_strcmp0 (s, "success") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test completed successfully"));
+ else if (g_strcmp0 (s, "aborted") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test was aborted"));
+ else if (g_strcmp0 (s, "interrupted") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test was interrupted"));
+ else if (g_strcmp0 (s, "fatal") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test did not complete"));
+ else if (g_strcmp0 (s, "error_unknown") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test failed"));
+ else if (g_strcmp0 (s, "error_electrical") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test failed (electrical)"));
+ else if (g_strcmp0 (s, "error_servo") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test failed (servo)"));
+ else if (g_strcmp0 (s, "error_read") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test failed (read)"));
+ else if (g_strcmp0 (s, "error_handling") == 0)
+ ret = g_strdup (C_("smart-self-test-result", "Last self-test failed (handling)"));
+ else if (g_strcmp0 (s, "inprogress") == 0)
+ {
+ ret = g_strdup_printf (C_("smart-self-test-result", "A self-test is in progress (%d%% remaining)"),
+ udisks_drive_ata_get_smart_selftest_percent_remaining (data->ata));
+ selftest_running = TRUE;
+ }
+ else
+ ret = g_strdup_printf (C_("smart-self-test-result", "Unknown (%s)"), s);
+
+ if (out_selftest_running)
+ *out_selftest_running = selftest_running;
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+enum
+{
+ ID_COLUMN,
+ DESC_COLUMN,
+ ASSESSMENT_COLUMN,
+ VALUE_COLUMN,
+ VALUE2_COLUMN,
+ TOOLTIP_COLUMN,
+ N_COLUMNS,
+};
+
+static void
+update_updated_label (DialogData *data)
+{
+ time_t now;
+ time_t updated;
+ gchar *s;
+
+ now = time (NULL);
+ updated = udisks_drive_ata_get_smart_updated (data->ata);
+ s = age_to_string (now - updated);
+ gtk_label_set_text (GTK_LABEL (data->updated_label), s);
+ g_free (s);
+}
+
+static gchar *
+format_temp (UDisksDriveAta *ata)
+{
+ gdouble temp;
+ gchar *ret = NULL;
+
+ temp = udisks_drive_ata_get_smart_temperature (ata);
+ if (temp > 1.0)
+ {
+ gdouble celcius;
+ gdouble fahrenheit;
+
+ celcius = temp - 273.15;
+ fahrenheit = 9.0 * celcius / 5.0 + 32.0;
+ /* Translators: Used to format a temperature.
+ * The first %f is the temperature in degrees Celcius and
+ * the second %f is the temperature in degrees Fahrenheit.
+ */
+ ret = g_strdup_printf (_("%.0f C / %.0f F"), celcius, fahrenheit);
+ }
+ return ret;
+}
+
+static gchar *
+format_powered_on (UDisksDriveAta *ata)
+{
+ guint64 secs;
+ gchar *ret = NULL;
+
+ secs = udisks_drive_ata_get_smart_power_on_seconds (ata);
+ if (secs > 0)
+ ret = format_duration_msec (secs * 1000);
+ return ret;
+}
+
+gchar *
+gdu_ata_smart_get_overall_assessment (UDisksDriveAta *ata,
+ gboolean include_temperature,
+ gboolean *out_smart_is_supported)
+{
+ gchar *ret;
+ gint num_failing;
+ gint num_failed_in_the_past;
+ gint num_bad_sectors;
+ gboolean smart_is_supported = FALSE;
+
+ if (!udisks_drive_ata_get_smart_supported (ata))
+ {
+ /* Translators: XXX */
+ ret = g_strdup (_("SMART is not supported"));
+ goto out_no_smart;
+ }
+
+ if (!udisks_drive_ata_get_smart_enabled (ata))
+ {
+ /* Translators: XXX */
+ ret = g_strdup (_("SMART is not enabled"));
+ goto out_no_smart;
+ }
+
+ smart_is_supported = TRUE;
+
+ num_failing = udisks_drive_ata_get_smart_num_attributes_failing (ata);
+ num_failed_in_the_past = udisks_drive_ata_get_smart_num_attributes_failed_in_the_past (ata);
+ num_bad_sectors = udisks_drive_ata_get_smart_num_bad_sectors (ata);
+
+ /* If self-assessment indicates failure, just return that */
+ if (udisks_drive_ata_get_smart_failing (ata))
+ {
+ ret = g_strdup_printf ("<span foreground=\"#ff0000\"><b>%s</b></span>",
+ /* Translators: XXX */
+ _("DISK IS LIKELY TO FAIL SOON"));
+ goto out;
+ }
+
+ /* Otherwise, if an attribute is failing, return that */
+ if (num_failing > 0)
+ {
+ /* Translators: XXX */
+ ret = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "Disk is OK, one failing attribute is failing",
+ "Disk is OK, %d attributes are failing",
+ num_failing),
+ num_failing);
+ goto out;
+ }
+
+ /* Otherwise, if bad sectors have been detected, return that */
+ if (num_bad_sectors > 0)
+ {
+ /* Translators: XXX */
+ ret = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "Disk is OK, one bad sector",
+ "Disk is OK, %d bad sectors",
+ num_bad_sectors),
+ num_bad_sectors);
+ goto out;
+ }
+
+ /* Otherwise, if an attribute has failed in the past return that */
+ if (num_failed_in_the_past > 0)
+ {
+ /* Translators: XXX */
+ ret = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "Disk is OK, one attribute failed in the past",
+ "Disk is OK, %d attributes failed in the past",
+ num_failed_in_the_past),
+ num_failed_in_the_past);
+ goto out;
+ }
+
+ /* Otherwise, it's all honky dory */
+
+ /* Translators: XXX */
+ ret = g_strdup ("Disk is OK");
+
+ out:
+
+ if (include_temperature)
+ {
+ gchar *s, *s1;
+ s = format_temp (ata);
+ if (s != NULL)
+ {
+ /* Translators: Used to convey the status and temperature in one line.
+ * The first %s is the status of the drive.
+ * The second %s is the temperature of the drive.
+ */
+ s1 = g_strdup_printf (_("%s (%s)"), ret, s);
+ g_free (ret);
+ ret = s1;
+ }
+ }
+
+ out_no_smart:
+ if (out_smart_is_supported != NULL)
+ *out_smart_is_supported = smart_is_supported;
+ return ret;
+}
+
+static void
+update_dialog (DialogData *data)
+{
+ gchar *s;
+ GVariant *attributes = NULL;
+ GError *error;
+ GtkTreeIter tree_iter;
+ GtkTreeIter *tree_iter_to_select;
+ gint selected_id;
+ gboolean selftest_running;
+
+ /* TODO: do it async and show spinner while call is pending */
+ error = NULL;
+ if (!udisks_drive_ata_call_smart_get_attributes_sync (udisks_object_peek_drive_ata (data->object),
+ g_variant_new ("a{sv}", NULL), /* options */
+ &attributes,
+ NULL, /* GCancellable */
+ &error))
+ {
+ g_warning ("Error getting ATA SMART information: %s (%s, %d)",
+ error->message, g_quark_to_string (error->domain), error->code);
+ g_error_free (error);
+ }
+
+ update_updated_label (data);
+
+ s = calculate_self_test (data, &selftest_running);
+ gtk_label_set_text (GTK_LABEL (data->self_test_label), s);
+ g_free (s);
+
+ if (selftest_running)
+ {
+ gtk_widget_set_visible (data->start_selftest_button, FALSE);
+ gtk_widget_set_visible (data->stop_selftest_button, TRUE);
+ }
+ else
+ {
+ gtk_widget_set_visible (data->start_selftest_button, TRUE);
+ gtk_widget_set_visible (data->stop_selftest_button, FALSE);
+ }
+
+ /* record currently selected row so we can reselect it */
+ selected_id = -1;
+ tree_iter_to_select = NULL;
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->attributes_treeview)),
+ NULL,
+ &tree_iter))
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (data->attributes_list),
+ &tree_iter,
+ ID_COLUMN, &selected_id,
+ -1);
+ }
+
+ gtk_list_store_clear (data->attributes_list);
+ if (attributes != NULL)
+ {
+ GVariantIter iter;
+ guchar id;
+ const gchar *name;
+ guint16 flags;
+ gint current, worst, threshold;
+ guint64 pretty; gint pretty_unit;
+ GVariant *expansion;
+
+ g_variant_iter_init (&iter, attributes);
+ while (g_variant_iter_next (&iter,
+ "(y&sqiiixi a{sv})",
+ &id,
+ &name,
+ &flags,
+ ¤t, &worst, &threshold,
+ &pretty, &pretty_unit,
+ &expansion))
+ {
+ GtkTreeIter titer;
+ gchar *desc_str;
+ gchar *assessment_str;
+ gchar *value_str;
+ gchar *value2_str;
+ gchar *tooltip_str;
+
+ desc_str = attr_format_desc (id, name);
+ assessment_str = attr_format_assessment (current, worst, threshold, flags);
+ value_str = attr_format_value (current, worst, threshold, pretty, pretty_unit, &value2_str);
+ tooltip_str = attr_format_tooltip (id, name, flags);
+
+ gtk_list_store_append (data->attributes_list, &titer);
+ gtk_list_store_set (data->attributes_list, &titer,
+ ID_COLUMN, (gint) id,
+ DESC_COLUMN, desc_str,
+ ASSESSMENT_COLUMN, assessment_str,
+ VALUE_COLUMN, value_str,
+ VALUE2_COLUMN, value2_str,
+ TOOLTIP_COLUMN, tooltip_str,
+ -1);
+
+ if (id == selected_id)
+ tree_iter_to_select = gtk_tree_iter_copy (&titer);
+
+ g_free (desc_str);
+ g_free (assessment_str);
+ g_free (value_str);
+ g_free (value2_str);
+ g_free (tooltip_str);
+
+ g_variant_unref (expansion);
+ }
+ }
+
+ /* reselect the previously selected row */
+ if (tree_iter_to_select != NULL)
+ {
+ gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->attributes_treeview)),
+ tree_iter_to_select);
+ gtk_tree_iter_free (tree_iter_to_select);
+ }
+ else
+ {
+ GtkTreeIter titer;
+ /* or the first row, if the previously selected one does not exist anymore */
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (data->attributes_list), &titer))
+ {
+ gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->attributes_treeview)),
+ &titer);
+ }
+ }
+
+ if (udisks_drive_ata_get_smart_failing (data->ata))
+ {
+ /* Translators: XXX */
+ s = g_strdup (_("Threshold exceeded"));
+ }
+ else
+ {
+ /* Translators: XXX */
+ s = g_strdup (_("Threshold not exceeded"));
+ }
+ gtk_label_set_markup (GTK_LABEL (data->self_assessment_label), s);
+ g_free (s);
+
+ s = format_powered_on (data->ata);
+ if (s == NULL)
+ s = g_strdup ("â");
+ gtk_label_set_markup (GTK_LABEL (data->powered_on_label), s);
+ g_free (s);
+
+ s = format_temp (data->ata);
+ if (s == NULL)
+ s = g_strdup ("â");
+ gtk_label_set_markup (GTK_LABEL (data->temperature_label), s);
+ g_free (s);
+
+ s = gdu_ata_smart_get_overall_assessment (data->ata, FALSE, NULL);
+ gtk_label_set_markup (GTK_LABEL (data->overall_assessment_label), s);
+ g_free (s);
+
+ if (attributes != NULL)
+ g_variant_unref (attributes);
+}
+
+/* called when properties on the Drive.Ata object changes */
+static void
+on_ata_notify (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ update_dialog (data);
+}
+
+/* called every second */
+static gboolean
+on_timeout (gpointer user_data)
+{
+ DialogData *data = user_data;
+ update_updated_label (data);
+ return TRUE; /* keep timeout around */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+smart_cancel_cb (UDisksDriveAta *ata,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GduWindow *window = GDU_WINDOW (user_data);
+ GError *error;
+
+ error = NULL;
+ if (!udisks_drive_ata_call_smart_selftest_abort_finish (ata, res, &error))
+ {
+ gdu_window_show_error (window,
+ _("Error aborting SMART self-test"),
+ error);
+ g_error_free (error);
+ }
+ g_object_unref (window);
+}
+
+static void
+smart_start_cb (UDisksDriveAta *ata,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GduWindow *window = GDU_WINDOW (user_data);
+ GError *error;
+
+ error = NULL;
+ if (!udisks_drive_ata_call_smart_selftest_start_finish (ata, res, &error))
+ {
+ gdu_window_show_error (window,
+ _("Error starting SMART self-test"),
+ error);
+ g_error_free (error);
+ }
+ g_object_unref (window);
+}
+
+
+static void
+selftest_do (DialogData *data,
+ const gchar *type)
+{
+ if (g_strcmp0 (type, "abort") == 0)
+ {
+ udisks_drive_ata_call_smart_selftest_abort (data->ata,
+ g_variant_new ("a{sv}", NULL), /* options */
+ NULL, /* GCancellable */
+ (GAsyncReadyCallback) smart_cancel_cb,
+ g_object_ref (data->window));
+ }
+ else
+ {
+ udisks_drive_ata_call_smart_selftest_start (data->ata,
+ type,
+ g_variant_new ("a{sv}", NULL), /* options */
+ NULL, /* GCancellable */
+ (GAsyncReadyCallback) smart_start_cb,
+ g_object_ref (data->window));
+ }
+}
+
+static void
+on_selftest_short (GtkMenuItem *menu_item,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ selftest_do (data, "short");
+}
+
+static void
+on_selftest_extended (GtkMenuItem *menu_item,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ selftest_do (data, "extended");
+}
+
+static void
+on_selftest_conveyance (GtkMenuItem *menu_item,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ selftest_do (data, "conveyance");
+}
+
+void
+gdu_ata_smart_dialog_show (GduWindow *window,
+ UDisksObject *object)
+{
+ DialogData *data;
+ guint n;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ gulong notify_id;
+ guint timeout_id;
+
+ data = g_new0 (DialogData, 1);
+ data->object = g_object_ref (object);
+ data->ata = udisks_object_peek_drive_ata (data->object);
+ data->window = g_object_ref (window);
+
+ data->dialog = gdu_application_new_widget (gdu_window_get_application (window),
+ "smart-dialog.ui",
+ "dialog1",
+ &data->builder);
+ for (n = 0; widget_mapping[n].name != NULL; n++)
+ {
+ gpointer *p = (gpointer *) ((char *) data + widget_mapping[n].offset);
+ *p = GTK_WIDGET (gtk_builder_get_object (data->builder, widget_mapping[n].name));
+ }
+
+ data->attributes_list = gtk_list_store_new (N_COLUMNS,
+ G_TYPE_INT, /* id */
+ G_TYPE_STRING, /* name */
+ G_TYPE_STRING, /* assessment */
+ G_TYPE_STRING, /* value */
+ G_TYPE_STRING, /* value2 */
+ G_TYPE_STRING); /* tooltip */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->attributes_list),
+ ID_COLUMN,
+ GTK_SORT_ASCENDING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (data->attributes_treeview),
+ GTK_TREE_MODEL (data->attributes_list));
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (data->attributes_treeview), TRUE);
+ gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (data->attributes_treeview), TOOLTIP_COLUMN);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_append_column (GTK_TREE_VIEW (data->attributes_treeview), column);
+ /* Translators: This string is used as the column title in the treeview for the Attribute ID (0-255) */
+ gtk_tree_view_column_set_title (column, _("ID"));
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ g_object_set (G_OBJECT (renderer),
+ "yalign", 0.5,
+ NULL);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "markup", ID_COLUMN, NULL);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_append_column (GTK_TREE_VIEW (data->attributes_treeview), column);
+ /* Translators: This string is used as the column title in the treeview for the attribute name and description */
+ gtk_tree_view_column_set_title (column, _("Attribute"));
+ gtk_tree_view_column_set_expand (column, TRUE);
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (G_OBJECT (renderer),
+ "yalign", 0.5,
+ "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
+ NULL);
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "markup", DESC_COLUMN, NULL);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_append_column (GTK_TREE_VIEW (data->attributes_treeview), column);
+ /* Translators: This string is used as the column title in the treeview for the assessment of the attribute */
+ gtk_tree_view_column_set_title (column, _("Assessment"));
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ g_object_set (G_OBJECT (renderer),
+ "yalign", 0.5,
+ NULL);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "markup", ASSESSMENT_COLUMN, NULL);
+
+ column = gtk_tree_view_column_new ();
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (data->attributes_treeview), column);
+ /* Translators: This string is used as the column title in the treeview for the value of the attribute */
+ gtk_tree_view_column_set_title (column, _("Value"));
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ g_object_set (G_OBJECT (renderer),
+ "yalign", 0.0,
+ NULL);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "markup", VALUE_COLUMN, NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ g_object_set (G_OBJECT (renderer),
+ "yalign", 0.0,
+ NULL);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "markup", VALUE2_COLUMN, NULL);
+
+
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (window));
+
+ notify_id = g_signal_connect (data->ata, "notify", G_CALLBACK (on_ata_notify), data);
+ timeout_id = g_timeout_add_seconds (1, on_timeout, data);
+
+ g_signal_connect (data->selftest_short_menuitem, "activate", G_CALLBACK (on_selftest_short), data);
+ g_signal_connect (data->selftest_extended_menuitem, "activate", G_CALLBACK (on_selftest_extended), data);
+ g_signal_connect (data->selftest_conveyance_menuitem, "activate", G_CALLBACK (on_selftest_conveyance), data);
+
+ data->start_selftest_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), 0);
+ data->stop_selftest_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), 1);
+
+ update_dialog (data);
+
+ while (TRUE)
+ {
+ gint response;
+ response = gtk_dialog_run (GTK_DIALOG (data->dialog));
+ switch (response)
+ {
+ case 0:
+ gtk_menu_popup (GTK_MENU (data->selftest_menu), NULL, NULL, NULL, NULL, 1, 0);
+ break;
+ case 1:
+ selftest_do (data, "abort");
+ break;
+ }
+
+ if (response < 0)
+ break;
+ }
+
+ g_source_remove (timeout_id);
+ g_signal_handler_disconnect (data->ata, notify_id);
+
+ dialog_data_free (data);
+}
diff --git a/src/palimpsest/gduatasmartdialog.h b/src/palimpsest/gduatasmartdialog.h
new file mode 100644
index 0000000..dce1d67
--- /dev/null
+++ b/src/palimpsest/gduatasmartdialog.h
@@ -0,0 +1,40 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_ATA_SMART_DIALOG_H_H__
+#define __GDU_ATA_SMART_DIALOG_H_H__
+
+#include <gtk/gtk.h>
+#include "gdutypes.h"
+
+G_BEGIN_DECLS
+
+void gdu_ata_smart_dialog_show (GduWindow *window,
+ UDisksObject *object);
+
+gchar *gdu_ata_smart_get_overall_assessment (UDisksDriveAta *ata,
+ gboolean include_temperature,
+ gboolean *out_smart_is_supported);
+
+G_END_DECLS
+
+#endif /* __GDU_ATA_SMART_DIALOG_H__ */
diff --git a/src/palimpsest/gduwindow.c b/src/palimpsest/gduwindow.c
index 13d19fd..bef6108 100644
--- a/src/palimpsest/gduwindow.c
+++ b/src/palimpsest/gduwindow.c
@@ -37,6 +37,7 @@
#include "gdudevicetreemodel.h"
#include "gduutils.h"
#include "gduvolumegrid.h"
+#include "gduatasmartdialog.h"
/* Keep in sync with tabs in palimpsest.ui file */
typedef enum
@@ -87,6 +88,7 @@ struct _GduWindow
GtkWidget *devtab_toolbar_deactivate_swap_button;
GtkWidget *generic_menu;
+ GtkWidget *generic_menu_item_view_smart;
GtkWidget *generic_menu_item_configure_fstab;
GtkWidget *generic_menu_item_configure_crypttab;
GtkWidget *generic_menu_item_edit_label;
@@ -123,6 +125,7 @@ static const struct {
{G_STRUCT_OFFSET (GduWindow, devtab_toolbar_activate_swap_button), "devtab-action-activate-swap"},
{G_STRUCT_OFFSET (GduWindow, devtab_toolbar_deactivate_swap_button), "devtab-action-deactivate-swap"},
{G_STRUCT_OFFSET (GduWindow, generic_menu), "generic-menu"},
+ {G_STRUCT_OFFSET (GduWindow, generic_menu_item_view_smart), "generic-menu-item-view-smart"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_configure_fstab), "generic-menu-item-configure-fstab"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_configure_crypttab), "generic-menu-item-configure-crypttab"},
{G_STRUCT_OFFSET (GduWindow, generic_menu_item_edit_label), "generic-menu-item-edit-label"},
@@ -155,16 +158,13 @@ typedef enum
SHOW_FLAGS_ENCRYPTED_UNLOCK_BUTTON = (1<<7),
SHOW_FLAGS_ENCRYPTED_LOCK_BUTTON = (1<<8),
- SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB = (1<<9),
- SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB = (1<<10),
- SHOW_FLAGS_POPUP_MENU_EDIT_LABEL = (1<<11),
- SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION = (1<<12),
+ SHOW_FLAGS_POPUP_MENU_VIEW_SMART = (1<<9),
+ SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB = (1<<10),
+ SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB = (1<<11),
+ SHOW_FLAGS_POPUP_MENU_EDIT_LABEL = (1<<12),
+ SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION = (1<<13),
} ShowFlags;
-static void gdu_window_show_error (GduWindow *window,
- const gchar *message,
- GError *orig_error);
-
static void setup_device_page (GduWindow *window, UDisksObject *object);
static void update_device_page (GduWindow *window, ShowFlags *show_flags);
static void teardown_device_page (GduWindow *window);
@@ -182,6 +182,8 @@ static void on_devtab_action_lock_activated (GtkAction *action, gpointer user_da
static void on_devtab_action_activate_swap_activated (GtkAction *action, gpointer user_data);
static void on_devtab_action_deactivate_swap_activated (GtkAction *action, gpointer user_data);
+static void on_generic_menu_item_view_smart (GtkMenuItem *menu_item,
+ gpointer user_data);
static void on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
gpointer user_data);
static void on_generic_menu_item_configure_crypttab (GtkMenuItem *menu_item,
@@ -325,6 +327,8 @@ update_for_show_flags (GduWindow *window,
gtk_action_set_visible (GTK_ACTION (window->devtab_toolbar_lock_button),
show_flags & SHOW_FLAGS_ENCRYPTED_LOCK_BUTTON);
+ gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_view_smart),
+ show_flags & SHOW_FLAGS_POPUP_MENU_VIEW_SMART);
gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_configure_fstab),
show_flags & SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB);
gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_configure_crypttab),
@@ -872,6 +876,10 @@ gdu_window_constructed (GObject *object)
G_CALLBACK (on_devtab_action_deactivate_swap_activated),
window);
+ g_signal_connect (window->generic_menu_item_view_smart,
+ "activate",
+ G_CALLBACK (on_generic_menu_item_view_smart),
+ window);
g_signal_connect (window->generic_menu_item_configure_fstab,
"activate",
G_CALLBACK (on_generic_menu_item_configure_fstab),
@@ -1213,12 +1221,16 @@ update_all (GduWindow *window,
case DETAILS_PAGE_DEVICE:
/* this is a little too inclusive.. */
- if (object != NULL && gdu_volume_grid_includes_object (GDU_VOLUME_GRID (window->volume_grid), object))
+ if (object != NULL)
{
- ShowFlags show_flags;
- show_flags = SHOW_FLAGS_NONE;
- update_details_page (window, window->current_page, &show_flags);
- update_for_show_flags (window, show_flags);
+ if (object == window->current_object ||
+ gdu_volume_grid_includes_object (GDU_VOLUME_GRID (window->volume_grid), object))
+ {
+ ShowFlags show_flags;
+ show_flags = SHOW_FLAGS_NONE;
+ update_details_page (window, window->current_page, &show_flags);
+ update_for_show_flags (window, show_flags);
+ }
}
break;
}
@@ -1423,74 +1435,14 @@ update_device_page_for_drive (GduWindow *window,
if (ata != NULL && !udisks_drive_get_media_removable (drive))
{
- gchar *s2 = NULL;
- gchar *s3 = NULL;
- if (!udisks_drive_ata_get_smart_supported (ata))
- {
- s = g_strdup (_("S.M.A.R.T. not supported"));
- }
- else if (!udisks_drive_ata_get_smart_enabled (ata))
- {
- s = g_strdup (_("S.M.A.R.T. not enabled"));
- }
- else
- {
- guint64 updated;
-
- updated = udisks_drive_ata_get_smart_updated (ata);
- if (updated == 0)
- {
- s = g_strdup (_("S.M.A.R.T. data not collected"));
- }
- else
- {
- gboolean failing;
- gdouble temp;
-
- failing = udisks_drive_ata_get_smart_failing (ata);
- if (failing)
- {
- s = g_strdup_printf ("<b><span foreground=\"#ff0000\">%s</span></b>",
- _("ABOUT TO FAIL"));
- }
- else
- {
- s = g_strdup (_("No problems detected"));
- }
- /* TODO: Also show
- * - if one or more prefail attrs are exceeding threshold
- * - if a self-test is in progress
- */
-
- temp = udisks_drive_ata_get_smart_temperature (ata);
- if (temp > 1.0)
- {
- gdouble celcius;
- gdouble fahrenheit;
- celcius = temp - 273.15;
- fahrenheit = 9.0 * celcius / 5.0 + 32.0;
- /* Translators: Used to convey the temperature of a drive.
- * The first %f is the temperature in degrees Celcius and the second %f
- * is the temperature in degrees Fahrenheit
- */
- s2 = g_strdup_printf (_("%.0f C / %.0f F"), celcius, fahrenheit);
- }
- }
- }
- if (s2 != NULL)
- {
- s3 = g_strdup_printf ("%s (%s)", s, s2);
- }
- else
- {
- s3 = g_strdup (s);
- }
+ gboolean smart_is_supported;
+ s = gdu_ata_smart_get_overall_assessment (ata, TRUE, &smart_is_supported);
set_markup (window,
"devtab-drive-smart-label",
"devtab-drive-smart-value-label",
- s3, SET_MARKUP_FLAGS_NONE);
- g_free (s3);
- g_free (s2);
+ s, SET_MARKUP_FLAGS_NONE);
+ if (smart_is_supported)
+ *show_flags |= SHOW_FLAGS_POPUP_MENU_VIEW_SMART;
g_free (s);
}
@@ -2111,24 +2063,24 @@ teardown_device_page (GduWindow *window)
/* ---------------------------------------------------------------------------------------------------- */
/* TODO: right now we show a MessageDialog but we could do things like an InfoBar etc */
-static void
+void
gdu_window_show_error (GduWindow *window,
const gchar *message,
- GError *orig_error)
+ GError *error)
{
GtkWidget *dialog;
- GError *error;
+ GError *fixed_up_error;
/* Never show an error if it's because the user dismissed the
* authentication dialog himself
*/
- if (orig_error->domain == UDISKS_ERROR &&
- orig_error->code == UDISKS_ERROR_NOT_AUTHORIZED_DISMISSED)
+ if (error->domain == UDISKS_ERROR &&
+ error->code == UDISKS_ERROR_NOT_AUTHORIZED_DISMISSED)
goto no_dialog;
- error = g_error_copy (orig_error);
- if (g_dbus_error_is_remote_error (error))
- g_dbus_error_strip_remote_error (error);
+ fixed_up_error = g_error_copy (error);
+ if (g_dbus_error_is_remote_error (fixed_up_error))
+ g_dbus_error_strip_remote_error (fixed_up_error);
dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
GTK_DIALOG_MODAL,
@@ -2138,8 +2090,8 @@ gdu_window_show_error (GduWindow *window,
message);
gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
"%s",
- error->message);
- g_error_free (error);
+ fixed_up_error->message);
+ g_error_free (fixed_up_error);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
@@ -2993,6 +2945,16 @@ on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
/* ---------------------------------------------------------------------------------------------------- */
+static void
+on_generic_menu_item_view_smart (GtkMenuItem *menu_item,
+ gpointer user_data)
+{
+ GduWindow *window = GDU_WINDOW (user_data);
+ gdu_ata_smart_dialog_show (window, window->current_object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
typedef struct
{
UDisksDrive *drive;
diff --git a/src/palimpsest/gduwindow.h b/src/palimpsest/gduwindow.h
index 8190eb0..da47aed 100644
--- a/src/palimpsest/gduwindow.h
+++ b/src/palimpsest/gduwindow.h
@@ -38,6 +38,10 @@ GduWindow *gdu_window_new (GduApplication *application,
GduApplication *gdu_window_get_application (GduWindow *window);
UDisksClient *gdu_window_get_client (GduWindow *window);
+void gdu_window_show_error (GduWindow *window,
+ const gchar *message,
+ GError *error);
+
G_END_DECLS
#endif /* __GDU_WINDOW_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]