mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-25 21:35:33 +00:00
Windows: SUpport tw_cli/cx/px variant of smartctl device if --scan-open fails
and tw_cli is installed.
This commit is contained in:
+3
-1
@@ -36,11 +36,13 @@ Bugs / patches:
|
||||
|
||||
TODO:
|
||||
|
||||
Windows: If smartctl --scan-open returns no "sd*,port"-style devices,
|
||||
+Windows: If smartctl --scan-open returns no "sd*,port"-style devices,
|
||||
check if 3dm2 is installed and execute "tw_cli show" to get the controllers,
|
||||
then use the tw_cli variant of smartctl.
|
||||
|
||||
|
||||
Support brief format of attributes (-f brief).
|
||||
At least as a parse-only thing (no sorting through columns)
|
||||
|
||||
|
||||
Testing:
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_DETECTOR_HELPERS_H
|
||||
#define STORAGE_DETECTOR_HELPERS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "executor_factory.h"
|
||||
#include "storage_device.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Get number of ports using tw_cli. Return -1 on error.
|
||||
inline std::string tw_cli_get_drives(const std::string& dev, int scsi_host_no,
|
||||
std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory, bool use_tw_cli_dev)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string command_options = hz::string_sprintf("/c%d show all", scsi_host_no);
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), command_options);
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
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(hz::string_trim_copy(lines.at(i)), &port_str, &status)) {
|
||||
if (status != "NOT-PRESENT") {
|
||||
int port = -1;
|
||||
hz::string_is_numeric(port_str, port);
|
||||
if (port != -1) {
|
||||
if (use_tw_cli_dev) { // use "tw_cli/cx/py" device
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice("tw_cli/c"
|
||||
+ hz::number_to_string(scsi_host_no) + "/p" + hz::number_to_string(port))));
|
||||
} else {
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(dev, "3ware," + hz::number_to_string(port))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Return 3ware SCSI host numbers (same as /c switch to tw_cli)
|
||||
/// \return error string on error
|
||||
inline std::string tw_cli_get_controllers(ExecutorFactoryRefPtr ex_factory, std::vector<int>& controllers)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), "show");
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
pcrecpp::RE controller_re = app_pcre_re("/^c([0-9])+[ \\t]+/mi");
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string controller_str;
|
||||
if (controller_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &controller_str)) {
|
||||
int controller = -1;
|
||||
hz::string_is_numeric(controller_str, controller);
|
||||
if (controller != -1) {
|
||||
controllers.push_back(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -12,14 +12,14 @@
|
||||
#include <algorithm> // std::find
|
||||
#include <cstdio> // std::fgets(), std::FILE
|
||||
#include <cerrno> // ENXIO
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs_path_utils.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector_helpers.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -211,71 +211,6 @@ inline std::string read_proc_scsi_scsi_file(std::vector<std::string>& lines)
|
||||
|
||||
|
||||
|
||||
/// Get number of ports using tw_cli. Return -1 on error.
|
||||
inline std::string tw_cli_get_drives(const std::string& dev, int scsi_host_no,
|
||||
std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string command_options = hz::string_sprintf("/c%d show all", scsi_host_no);
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), command_options);
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
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(hz::string_trim_copy(lines.at(i)), &port_str, &status)) {
|
||||
if (status != "NOT-PRESENT") {
|
||||
int port = -1;
|
||||
hz::string_is_numeric(port_str, port);
|
||||
if (port != -1) {
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(dev, "3ware," + hz::number_to_string(port))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Get number of ports by sequentially running smartctl on each port, until
|
||||
/// one of the gives an error. Return -1 on error.
|
||||
inline std::string smartctl_get_drives(const std::string& dev, const std::string& type,
|
||||
@@ -503,7 +438,7 @@ inline std::string detect_drives_linux_3ware(std::vector<StorageDeviceRefPtr>& d
|
||||
// We can't map twaX to scsiY, so lets assume the relative order is the same.
|
||||
std::string dev = std::string("/dev/") + (twa_found ? "twa" : "twe") + hz::number_to_string(num_controllers);
|
||||
|
||||
error_msg = tw_cli_get_drives(dev, last_scsi_host, drives, ex_factory);
|
||||
error_msg = tw_cli_get_drives(dev, last_scsi_host, drives, ex_factory, false);
|
||||
if (!error_msg.empty()) { // no tw_cli
|
||||
int max_ports = rconfig::get_data<int32_t>("system/linux_max_scan_ports");
|
||||
max_ports = std::max(max_ports, 23); // 128 smartctl calls are too much (it's too slow). Settle for 24.
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#include <windows.h> // CreateFileA(), CloseHandle(), etc...
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "hz/win32_tools.h"
|
||||
#include "hz/string_sprintf.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector_helpers.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -26,7 +28,7 @@ Call as: smartctl -i sd[a-z],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.
|
||||
tw_cli may be needed for older controllers / drivers.
|
||||
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.
|
||||
@@ -153,6 +155,7 @@ std::string detect_drives_win32(std::vector<StorageDeviceRefPtr>& drives, Execut
|
||||
{
|
||||
std::vector<int> used_pds;
|
||||
std::string error_msg = get_scan_open_multiport_devices(drives, ex_factory, used_pds);
|
||||
bool multiport_found = !drives.empty();
|
||||
|
||||
for (int drive_num = 0; ; ++drive_num) {
|
||||
std::string name = hz::string_sprintf("\\\\.\\PhysicalDrive%d", drive_num);
|
||||
@@ -176,6 +179,27 @@ std::string detect_drives_win32(std::vector<StorageDeviceRefPtr>& drives, Execut
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If smartctl --scan-open returns no "sd*,port"-style devices,
|
||||
// check if 3dm2 is installed and execute "tw_cli show" to get
|
||||
// the controllers, then use the tw_cli variant of smartctl.
|
||||
|
||||
if (!multiport_found) {
|
||||
std::string inst_path;
|
||||
hz::win32_get_registry_value_string(HKEY_USERS, ".DEFAULT\\Software\\3ware\\3DM2", "InstallPath", inst_path);
|
||||
|
||||
if (!inst_path.empty()) {
|
||||
std::vector<int> controllers;
|
||||
error_msg = tw_cli_get_controllers(ex_factory, controllers);
|
||||
// ignore the error message above, it's of no use.
|
||||
for (std::size_t i = 0; i < controllers.size(); ++i) {
|
||||
// don't specify device, it's ignored in tw_cli mode
|
||||
tw_cli_get_drives("", controllers.at(i), drives, ex_factory, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user