From 4000fa1a2ec63dab5c598c0e32e467ffd538096c Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Sun, 6 Mar 2011 17:15:56 +0000 Subject: [PATCH] Added the ability to configure default smartctl info save filename through config file. Use model-serial-date.txt for default save filename. --- gsmartcontrol/TODO | 74 ++++----------------- gsmartcontrol/src/applib/storage_device.cpp | 21 ++++-- gsmartcontrol/src/applib/storage_device.h | 8 +++ gsmartcontrol/src/gsc_settings.h | 2 + gsmartcontrol/src/hz/string_algo.h | 4 ++ 5 files changed, 42 insertions(+), 67 deletions(-) diff --git a/gsmartcontrol/TODO b/gsmartcontrol/TODO index aff47ff..e4504da 100644 --- a/gsmartcontrol/TODO +++ b/gsmartcontrol/TODO @@ -36,8 +36,6 @@ Bugs / patches: TODO: -+Clear the test message area when starting a new test. - Add debian/ubuntu's su-to-root support to gsmartcontrol-root. Testing: @@ -50,14 +48,8 @@ Testing: Add ability to configure default save filename (in config-file only?): "{serial}-{model}-{date}.txt", with the default being "{model}-{date}.txt". - -Add string_replace_linear(), where multiple strings are replaced into the - original string (as opposed to previous result). - -+Re-check long double printing - win32 libc doesn't support it, a cast - to double is needed. - The underlying problem is that in msvc, long double is the same size - as double, so printf() has mingw-incompatible presentation of long double. + Add string_replace_linear(), where multiple strings are replaced into the + original string (as opposed to previous result). Add support for launching with consolehelper (from usermode package). Fedora uses this by default. @@ -273,60 +265,18 @@ Add detection for Interix (i586-pc-interix3), maybe with debian? ------------ Feature List ---------- - -+Autodetect available devices - -+Select current device (from autodetected list; manually whitelist devices). - -+Smartctl binary (text entries in Options - binary, default command line options). -+ Global command-line options for smartctl. -+ Command-line options per-device in settings (e.g. -d ata). -+ Search smartctl binary on startup (try to execute it with --version). If it's not there, alert the user. - -+Indicate which of the devices has SMART supported / enabled. -+ Enable / disable smart on devices. -+ Indicate that this is until shutdown (but may be preserved on reboot). -+ Direct them to smartd / smartctl documentation for permanent enabling. -+ NOTE: SMART is sometimes preserved across power cycles. - -+Enable / disable Automatic Offline Data Collection for devices. (-o on) -+ Show its status in the main window. - -+Show identity information for device (aka short info), --info. - -+Show all SMART information for device (--all), includes: -+ * Short info (--info) -+ * SMART DATA -+ * overall-health (-H, --health) - may check this automatically as well. -+ * General SMART Values, aka Capabilities (-c, --capabilities) -+ * Attributes (-A, --attributes). These need decoding. -+ * Error Log (-l error) -+ * Self-test log (-l selftest) -+ * Selective self-test log and settings - * SCT status and other stuff - Display temperature somewhere (use SCT or Attr 194 for this). -+ * Ability to save this information to a file. -+ * On info window show: Ask to turn SMART on if it's disabled - -+Program error reporting: -+ invalid smartmontools version. -+ cannot parse output - show log. -+ smartctl exited with error - look it up in error map. +----------- SMART stuff ---------- - - -+Tests: - Run one-time Immediate Offline test (-t offline). - Offline tests only update Attributes, and if errors are found they will - appear in SMART error log. Self-test logs are unaffected. - Abort (-X). Abort works with Offline only if there's - "Abort Offline collection upon new command" capability. - If the drive has "Suspend Offline collection upon new command" capability, - immediate offline test may be tracked through --capabilities (not on mine!). - If it's "Abort Offline collection upon new command", then the test - will abort on --capabilities or --abort. +Run one-time Immediate Offline test (-t offline). + Offline tests only update Attributes, and if errors are found they will + appear in SMART error log. Self-test logs are unaffected. + Abort (-X). Abort works with Offline only if there's + "Abort Offline collection upon new command" capability. + If the drive has "Suspend Offline collection upon new command" capability, + immediate offline test may be tracked through --capabilities (not on mine!). + If it's "Abort Offline collection upon new command", then the test + will abort on --capabilities or --abort. Polling time diff --git a/gsmartcontrol/src/applib/storage_device.cpp b/gsmartcontrol/src/applib/storage_device.cpp index 2613a25..ce2a5b4 100644 --- a/gsmartcontrol/src/applib/storage_device.cpp +++ b/gsmartcontrol/src/applib/storage_device.cpp @@ -122,6 +122,11 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si family_name_ = hz::string_remove_adjacent_duplicates_copy(hz::string_trim_copy(family), ' '); } + std::string serial; + if (app_pcre_match("/^Serial Number:[ \\t]*(.*)$/mi", info_output_, &serial)) { + serial_number_ = hz::string_remove_adjacent_duplicates_copy(hz::string_trim_copy(serial), ' '); + } + // Note: this property is present since 5.33. std::string size; @@ -422,11 +427,17 @@ StorageProperty StorageDevice::get_health_property() const std::string StorageDevice::get_save_filename() const { - std::string filename = this->get_model_name(); // may be empty - filename += hz::format_date("-%Y-%m-%d", false); - if (!filename.empty()) - filename = hz::filename_make_safe(filename) + ".txt"; - return filename; + std::string model = this->get_model_name(); // may be empty + std::string serial = this->get_serial_number(); + std::string date = hz::format_date("%Y-%m-%d", false); + + std::string filename_format; + rconfig::get_data("gui/smartctl_output_filename_format", filename_format); + hz::string_replace(filename_format, "{serial}", serial); + hz::string_replace(filename_format, "{model}", model); + hz::string_replace(filename_format, "{date}", date); + + return hz::filename_make_safe(filename_format); } diff --git a/gsmartcontrol/src/applib/storage_device.h b/gsmartcontrol/src/applib/storage_device.h index f23be75..c06e32f 100644 --- a/gsmartcontrol/src/applib/storage_device.h +++ b/gsmartcontrol/src/applib/storage_device.h @@ -304,6 +304,13 @@ class StorageDevice : public hz::intrusive_ptr_referenced { } + // returns an empty string if unknown + std::string get_serial_number() const + { + return (serial_number_.defined() ? serial_number_.value() : ""); + } + + void set_info_output(const std::string& s) { info_output_ = s; @@ -398,6 +405,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced { mutable hz::OptionalValue aodc_status_; // cached aodc status. hz::OptionalValue model_name_; hz::OptionalValue family_name_; + hz::OptionalValue serial_number_; hz::OptionalValue size_; // formatted size mutable hz::OptionalValue health_property_; // cached health property. diff --git a/gsmartcontrol/src/gsc_settings.h b/gsmartcontrol/src/gsc_settings.h index 58d66f7..3add462 100644 --- a/gsmartcontrol/src/gsc_settings.h +++ b/gsmartcontrol/src/gsc_settings.h @@ -54,6 +54,8 @@ inline void init_default_settings() rconfig::set_default_data("gui/show_smart_capable_only", false); // show smart-capable drives only rconfig::set_default_data("gui/scan_on_startup", true); // scan drives on startup + rconfig::set_default_data("gui/smartctl_output_filename_format", "{model}_{serial}_{date}.txt"); // when suggesting filename + // Populate /runtime too, just in case. The values don't really matter. diff --git a/gsmartcontrol/src/hz/string_algo.h b/gsmartcontrol/src/hz/string_algo.h index 0c7baae..eaade6e 100644 --- a/gsmartcontrol/src/hz/string_algo.h +++ b/gsmartcontrol/src/hz/string_algo.h @@ -355,6 +355,10 @@ inline std::string string_remove_adjacent_duplicates_copy(const std::string& s, // --------------------------------------------- Replace +// TODO: Add string_replace_linear(), where multiple strings are replaced into the +// original string (as opposed to previous result). + + // Replace from with to inside s (modifying s). Return number of replacements made. inline std::string::size_type string_replace(std::string& s, const std::string& from, const std::string& to, int max_replacements = -1)