From 5e46ed7cb6322ac28d9662af02099f5b4e1fdaab Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Sun, 17 Apr 2011 20:36:54 +0000 Subject: [PATCH] Added support for devices detected by "smartctl --scan-open" under win32 (this includes 3ware). --- gsmartcontrol/TODO | 28 +--- .../src/applib/storage_detector_linux.cpp | 2 +- .../src/applib/storage_detector_win32.cpp | 130 +++++++++++++++++- 3 files changed, 133 insertions(+), 27 deletions(-) diff --git a/gsmartcontrol/TODO b/gsmartcontrol/TODO index 45a4824..a4408f0 100644 --- a/gsmartcontrol/TODO +++ b/gsmartcontrol/TODO @@ -42,6 +42,8 @@ Add debian/ubuntu's su-to-root support to gsmartcontrol-root. Set tooltips wherever we have "No description available". +!!! Allow quitting when test is running (ask first). + Testing: If ETA time has elapsed, but it's still only at 10% completion, @@ -50,7 +52,7 @@ Testing: Can't reproduce it? Detect running tests on launch (maybe ask the user too? some tests may be stuck due to bad firmware). - Allow quitting when test is running (ask first). + Add support for launching with consolehelper (from usermode package). Fedora uses this by default. @@ -124,30 +126,6 @@ RAID: Call as: smartctl -i -d 3ware,[0-127] /dev/twa0 (or twe0) Detection: unknown. - 3ware Windows (XP so far, maybe the same under the others): - For 3ware 9xxx only. - Call as: smartctl -i sd[a-z],N - N is port, a-z is logical drive (unit) provided by controller. - N is limited to [0, 31] in the code. - The sd[a-z] device actually exists as \\.\PhysicalDrive[0-N]. - No idea how to check if it's 3ware. - Call as: smarctl -i tw_cli/cx/py - This runs tw_cli tool and parses the output; controller x, port y. - tw_cli is needed for 64-bit systems, as well as older controllers. - In tw_cli mode only limited information-gathering is supported. - tw_cli (part of 3DM2) is automatically added to system PATH, - no need to look for it. - 3DM2 install can be detected by checking: - HKEY_USERS\.DEFAULT\Software\3ware\3DM2, InstallPath - Another option for detection (whether it's 3ware) would be getting - \\.\PhysicalDrive0 properties, like smartctl does. - Newer (> 5.39.1) smartctl supports --scan-open, which will give us: - /dev/sda,0 -d ata (opened) - /dev/sda,1 -d ata (opened) - -d 3ware is not needed under Windows. We should treat sda as pd0 - and remove pd0 from PhysicalDrive-detected list. - Running smartctl on sda gives almost the same result as on sda,0. - LSI MegaRAID (SCSI/SAS), Linux: Call as: smartctl -i -d megaraid,[0-?] /dev/sda diff --git a/gsmartcontrol/src/applib/storage_detector_linux.cpp b/gsmartcontrol/src/applib/storage_detector_linux.cpp index 2d8b940..7fe84d3 100644 --- a/gsmartcontrol/src/applib/storage_detector_linux.cpp +++ b/gsmartcontrol/src/applib/storage_detector_linux.cpp @@ -260,7 +260,7 @@ inline std::string tw_cli_get_drives(const std::string& dev, int controller_no, pcrecpp::RE port_re = app_pcre_re("/^p([0-9])+[ \\t]+([^\\t\\n]+)/mi"); for (std::size_t i = 0; i < lines.size(); ++i) { std::string port_str, status; - if (port_re.PartialMatch(lines.at(i), &port_str, &status)) { + if (port_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &port_str, &status)) { if (status != "NOT-PRESENT") { int port = -1; hz::string_is_numeric(port_str, port); diff --git a/gsmartcontrol/src/applib/storage_detector_win32.cpp b/gsmartcontrol/src/applib/storage_detector_win32.cpp index 57811b3..e9bed89 100644 --- a/gsmartcontrol/src/applib/storage_detector_win32.cpp +++ b/gsmartcontrol/src/applib/storage_detector_win32.cpp @@ -9,8 +9,130 @@ #if defined CONFIG_KERNEL_FAMILY_WINDOWS #include // CreateFileA(), CloseHandle(), etc... +#include #include "hz/string_sprintf.h" +#include "rconfig/rconfig_mini.h" +#include "app_pcrecpp.h" + + +/* +3ware Windows (XP so far, maybe the same under the others): +For 3ware 9xxx only. +Call as: smartctl -i sd[a-z],N + N is port, a-z is logical drive (unit) provided by controller. + N is limited to [0, 31] in the code. + The sd[a-z] device actually exists as \\.\PhysicalDrive[0-N]. + No idea how to check if it's 3ware. +Call as: smarctl -i tw_cli/cx/py + This runs tw_cli tool and parses the output; controller x, port y. + tw_cli is needed for 64-bit systems, as well as older controllers. + In tw_cli mode only limited information-gathering is supported. +tw_cli (part of 3DM2) is automatically added to system PATH, + no need to look for it. +3DM2 install can be detected by checking: + HKEY_USERS\.DEFAULT\Software\3ware\3DM2, InstallPath +Another option for detection (whether it's 3ware) would be getting + \\.\PhysicalDrive0 properties, like smartctl does. +Newer (> 5.39.1) smartctl supports --scan-open, which will give us: + /dev/sda,0 -d ata (opened) + /dev/sda,1 -d ata (opened) +-d 3ware is not needed under Windows. We should treat sda as pd0 + and remove pd0 from PhysicalDrive-detected list. +Running smartctl on sda gives almost the same result as on sda,0. +*/ + + +/** + smartctl --scan-open output for win32 (3ware): + /dev/sda,0 -d ata (opened) + /dev/sda,1 -d ata (opened) + + smartctl --scan-open output for linux: + /dev/sda -d sat # /dev/sda [SAT], ATA device + /dev/sdb -d sat # /dev/sdb [SAT], ATA device + /dev/sdc -d sat # /dev/sdc [SAT], ATA device +*/ + + +namespace { + + + +/// Run "smartctl --scan-open" and pick the devices which have +/// a port parameter. We don't pick the others because the may +/// conflict with pd* devices, and we like pd* better than sd*. +std::string get_scan_open_multiport_devices(std::vector& drives, + ExecutorFactoryRefPtr ex_factory, std::vector& equivalent_pds) +{ + hz::intrusive_ptr smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl); + + std::string smartctl_binary = get_smartctl_binary(); + + if (smartctl_binary.empty()) { + debug_out_error("app", DBG_FUNC_MSG << "Smartctl binary is not set in config.\n"); + return "Smartctl binary is not specified in configuration."; + } + + std::string smartctl_def_options; + rconfig::get_data("system/smartctl_options", smartctl_def_options); + + if (!smartctl_def_options.empty()) + smartctl_def_options += " "; + + smartctl_ex->set_command(Glib::shell_quote(smartctl_binary), + smartctl_def_options + "--scan-open"); + + if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) { + debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n"); + return smartctl_ex->get_error_msg(); + } + + // any_to_unix is needed for windows + std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str())); + if (output.empty()) { + debug_out_error("app", DBG_FUNC_MSG << "Smartctl returned an empty output.\n"); + return "Smartctl returned an empty output."; + } + + // if we've reached smartctl port limit (older versions may have smaller limits), abort. + if (app_pcre_match("/UNRECOGNIZED OPTION/mi", output)) { + return "Smartctl doesn't support --scan-open switch."; + } + + std::vector lines; + hz::string_split(output, '\n', lines, true); + + +// /dev/sda,0 -d ata (opened) +// /dev/sda,1 -d ata (opened) +// /dev/sda -d sat # /dev/sda [SAT], ATA device + + // we only pick the ones with ports + pcrecpp::RE port_re = app_pcre_re("/^(\\/dev/\\[a-z0-9]),([0-9])+[ \\t]+-d[ \\t]+([^\\t\\n]+)/i"); + pcrecpp::RE dev_re = app_pcre_re("/^\\/dev\\/sd([a-z])$/"); + + for (std::size_t i = 0; i < lines.size(); ++i) { + std::string dev, port_str, type; + if (port_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &dev, &port_str, &type)) { + std::string letter; + if (dev_re.PartialMatch(dev, &letter)) { + // don't use pd* devices equivalent to these sd* devices. + equivalent_pds.push_back(letter.at(0) - 'a'); + } + + std::string full_dev = dev + "," + port_str; + drives.push_back(StorageDeviceRefPtr(new StorageDevice(full_dev, type))); + } + } + + return std::string(); +} + + + +} + @@ -21,6 +143,9 @@ std::string detect_drives_win32(std::vector& drives, ExecutorFactoryRefPtr ex_factory) { + std::vector used_pds; + std::string error_msg = get_scan_open_multiport_devices(drives, ex_factory, used_pds); + for (int drive_num = 0; ; ++drive_num) { std::string name = hz::string_sprintf("\\\\.\\PhysicalDrive%d", drive_num); @@ -37,7 +162,10 @@ std::string detect_drives_win32(std::vector& drives, Execut CloseHandle(h); - drives.push_back(new StorageDevice(hz::string_sprintf("pd%d", drive_num))); + if (std::find(used_pds.begin(), used_pds.end(), drive_num) == used_pds.end()) { + std::string dev = hz::string_sprintf("pd%d", drive_num); + drives.push_back(new StorageDevice(dev)); + } } return std::string();