Implemented detection of device type.

This commit is contained in:
Alexander Shaduri committed 2024-05-02 14:38:31 +04:00
1 parent 6594cddb65
commit c3a6f0b624
6 files changed
+74 -36

No files matched your search

+2 -2
View File
@@ -72,8 +72,6 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonBasicParser::parse_section_bas
{
using namespace SmartctlJsonParserHelpers;
// TODO CD/DVD, RAID
bool smart_supported = true; // TODO
bool smart_enabled = true; // TODO
@@ -97,6 +95,8 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonBasicParser::parse_section_bas
// 2. Present in devices for which we do not have specialized parsers (USB, etc.)
static const std::vector<std::tuple<std::string, std::string, PropertyRetrievalFunc>> info_keys = {
{"device/type", _("Smartctl Device Type"), string_formatter()}, // nvme, sat, etc.
{"vendor", _("Vendor"), string_formatter()}, // Flash drive
{"product", _("Product"), string_formatter()}, // Flash drive
+5
View File
@@ -11,12 +11,17 @@ Copyright:
#include <locale>
#include <cctype> // isspace
#include <utility>
#include <string_view>
#include "smartctl_parser.h"
#include "ata_storage_property.h"
#include "hz/error_container.h"
#include "smartctl_text_ata_parser.h"
#include "smartctl_json_ata_parser.h"
#include "smartctl_json_basic_parser.h"
#include "smartctl_text_basic_parser.h"
#include "storage_property_repository.h"
//#include "ata_storage_property_descr.h"
+1
View File
@@ -19,6 +19,7 @@ Copyright:
#include "smartctl_parser_types.h"
#include "ata_storage_property_descr.h"
#include "storage_device_detected_type.h"
+1
View File
@@ -12,6 +12,7 @@ Copyright:
#include "local_glibmm.h"
#include <gtkmm.h> // compose()
#include <algorithm>
#include <memory>
#include "build_config.h"
+21 -10
View File
@@ -9,25 +9,36 @@ Copyright:
/// \weakgroup applib
/// @{
#include "build_config.h"
#include "storage_detector_linux.h"
#include "command_executor.h"
#include "local_glibmm.h"
#include <algorithm> // std::find
#include <cstdio> // std::fgets(), std::FILE
// #include <cerrno> // ENXIO
#include <memory>
#include <pcrecpp.h>
#include <filesystem>
#include <set>
#include <map>
#include <system_error>
#include <vector>
#include <utility> // std::pair
#include <string>
#include "build_config.h"
#include "command_executor_factory.h"
#include "hz/error_container.h"
#include "hz/string_algo.h"
#include "hz/debug.h"
#include "hz/fs.h"
#include "hz/string_num.h"
#include "rconfig/rconfig.h"
#include "app_pcrecpp.h"
#include "storage_detector_linux.h"
#include "storage_detector.h"
#include "storage_detector_helpers.h"
#include "storage_device.h"
@@ -298,7 +309,7 @@ inline std::string read_proc_scsi_sg_devices_file(std::vector<std::vector<int>>&
R"(^([0-9-]+)\s+([0-9-]+)\s+([0-9-]+)\s+([0-9-]+)\s+([0-9-]+)\s+([0-9-]+)\s+([0-9-]+)\s+([0-9-]+)\s+([0-9-]+))");
for (std::size_t i = 0; i < lines.size(); ++i) {
std::string trimmed = hz::string_trim_copy(lines[i]);
const std::string trimmed = hz::string_trim_copy(lines[i]);
std::vector<std::string> line(9);
if (parse_re.PartialMatch(trimmed, &line[0], &line[1], &line[2], &line[3], &line[4], &line[5], &line[6], &line[7], &line[8])) {
std::vector<int> line_num(line.size(), -1);
@@ -371,7 +382,7 @@ inline hz::ExpectedVoid<StorageDetectorError> detect_drives_linux_proc_partition
debug_out_info("app", DBG_FUNC_MSG << "Detecting drives through partitions file (/proc/partitions by default; set \"system/linux_proc_partitions_path\" config key to override).\n");
std::vector<std::string> lines;
std::string error_msg = read_proc_partitions_file(lines);
const std::string error_msg = read_proc_partitions_file(lines);
if (!error_msg.empty()) {
return hz::Unexpected(StorageDetectorError::ProcReadError, error_msg);
}
@@ -410,7 +421,7 @@ inline hz::ExpectedVoid<StorageDetectorError> detect_drives_linux_proc_partition
if (blacked)
continue;
std::string path = "/dev/" + dev; // let's just hope it's really /dev.
const std::string path = "/dev/" + dev; // let's just hope it's really /dev.
if (std::find(devices.begin(), devices.end(), path) == devices.end()) { // there may be duplicates
devices.push_back(path);
}
@@ -525,7 +536,7 @@ inline hz::ExpectedVoid<StorageDetectorError> detect_drives_linux_3ware(
continue; // not a supported controller
}
int host_num = vendor_model.first;
const int host_num = vendor_model.first;
debug_out_dump("app", "Found LSI/AMCC/3ware controller in SCSI file, SCSI host " << host_num << ".\n");
@@ -557,7 +568,7 @@ inline hz::ExpectedVoid<StorageDetectorError> detect_drives_linux_3ware(
// else we default to twl, twa, twe (in this order)
}
// We can't map twaX to scsiY, so lets assume the relative order is the same.
// We can't map twaX to scsiY, so let's assume the relative order is the same.
std::string dev = std::string("/dev/") + dev_base + hz::number_to_string_nolocale(device_numbers[dev_base]);
++device_numbers[dev_base];
@@ -651,7 +662,7 @@ inline hz::ExpectedVoid<StorageDetectorError> detect_drives_linux_adaptec(
if (!app_pcre_match("/Vendor: Adaptec /i", vendors_model.second)) {
continue; // not a supported controller
}
int host_num = vendors_model.first;
const int host_num = vendors_model.first;
debug_out_dump("app", "Found Adaptec controller in SCSI file, SCSI host " << host_num << ".\n");
// Skip additional adapters with the same host, since they are the same adapters
@@ -673,11 +684,11 @@ inline hz::ExpectedVoid<StorageDetectorError> detect_drives_linux_adaptec(
continue;
}
std::string dev = std::string("/dev/sg") + hz::number_to_string_nolocale(sg_num);
const std::string dev = std::string("/dev/sg") + hz::number_to_string_nolocale(sg_num);
auto drive = std::make_shared<StorageDevice>(dev, std::string("sat"));
auto fetch_status = drive->fetch_basic_data_and_parse(smartctl_ex);
std::string output = drive->get_basic_output();
const std::string output = drive->get_basic_output();
// Note: Not sure about this, have to check with real SAS drives
if (app_pcre_match("/Device Read Identity Failed/mi", output)) {
+44 -24
View File
@@ -34,6 +34,7 @@ Copyright:
#include "smartctl_executor.h"
#include "smartctl_version_parser.h"
#include "ata_storage_property_descr.h"
#include "build_config.h"
//#include "smartctl_text_parser_helper.h"
//#include "ata_storage_property_descr.h"
@@ -160,7 +161,7 @@ hz::ExpectedVoid<StorageDeviceError> StorageDevice::parse_basic_data()
auto basic_parser = SmartctlParser::create(SmartctlParserType::Basic, SmartctlOutputFormat::Json);
DBG_ASSERT_RETURN(basic_parser, hz::Unexpected(StorageDeviceError::ParseError, _("Cannot create parser")));
// This also detects the drive type and adds it to "_custom/parser_detected_drive_type" property.
// This also fills the drive type properties.
auto parse_status = basic_parser->parse(this->get_basic_output());
if (!parse_status) {
return hz::Unexpected(StorageDeviceError::ParseError,
@@ -168,7 +169,7 @@ hz::ExpectedVoid<StorageDeviceError> StorageDevice::parse_basic_data()
}
// See if we can narrow down the drive type from what was detected
// by StorageDetector and "_custom/parser_detected_drive_type" property set by Basic parser.
// by StorageDetector and properties set by Basic parser.
auto basic_property_repo = basic_parser->get_property_repository();
// Make detected type more exact.
@@ -584,39 +585,58 @@ void StorageDevice::read_common_properties()
void StorageDevice::detect_drive_type_from_properties(const StoragePropertyRepository& property_repo)
{
auto drive_type_prop = property_repo.lookup_property("_custom/parser_detected_drive_type");
if (!drive_type_prop.empty()) {
// This is set by Text parser
if (auto drive_type_prop = property_repo.lookup_property("_custom/parser_detected_drive_type"); !drive_type_prop.empty()) {
const auto& drive_type_storable_str = drive_type_prop.get_value<std::string>();
set_detected_type(StorageDeviceDetectedTypeExt::get_by_storable_name(drive_type_storable_str, StorageDeviceDetectedType::BasicScsi));
}
switch (get_detected_type()) {
case StorageDeviceDetectedType::Unknown:
set_detected_type(StorageDeviceDetectedType::BasicScsi); // fall back to basic scsi parser
break;
case StorageDeviceDetectedType::AtaAny:
// Find out if it's SSD or HDD
{
// Find out if it's SSD or HDD
if (get_detected_type() == StorageDeviceDetectedType::AtaAny) {
auto rpm_prop = property_repo.lookup_property("rotation_rate");
if (rpm_prop.empty() || rpm_prop.get_value<std::int64_t>() == 0) {
set_detected_type(StorageDeviceDetectedType::AtaSsd);
} else {
set_detected_type(StorageDeviceDetectedType::AtaHdd);
}
break;
}
case StorageDeviceDetectedType::AtaHdd:
case StorageDeviceDetectedType::AtaSsd:
case StorageDeviceDetectedType::Nvme:
case StorageDeviceDetectedType::BasicScsi:
case StorageDeviceDetectedType::CdDvd:
case StorageDeviceDetectedType::UnsupportedRaid:
// leave as is
break;
case StorageDeviceDetectedType::NeedsExplicitType:
DBG_ASSERT(0);
break;
}
// This is set by JSON parser
if (auto device_type_prop = property_repo.lookup_property("device/type"); !device_type_prop.empty()) {
// Note: USB flash drives in non-scsi mode do not have this property.
const auto& smartctl_type = device_type_prop.get_value<std::string>();
if (smartctl_type == "scsi") { // USB flash in scsi mode, optical, scsi, etc.
if (BuildEnv::is_kernel_linux() && get_device_base().starts_with("sr")) {
set_detected_type(StorageDeviceDetectedType::CdDvd);
} else {
set_detected_type(StorageDeviceDetectedType::BasicScsi);
}
} else if (smartctl_type == "sat") { // (S)ATA, including behind supported RAID controllers
// Find out if it's SSD or HDD
auto rpm_prop = property_repo.lookup_property("rotation_rate");
if (rpm_prop.empty() || rpm_prop.get_value<std::int64_t>() == 0) {
set_detected_type(StorageDeviceDetectedType::AtaSsd);
} else {
set_detected_type(StorageDeviceDetectedType::AtaHdd);
}
} else if (smartctl_type == "nvme") { // NVMe SSD
set_detected_type(StorageDeviceDetectedType::Nvme);
} else {
// TODO Detect unsupported RAID
debug_out_warn("app", "Unsupported type " << smartctl_type << " reported by smartctl for " << get_device_with_type() << "\n");
}
}
if (get_detected_type() == StorageDeviceDetectedType::Unknown) {
set_detected_type(StorageDeviceDetectedType::BasicScsi); // fall back to basic scsi parser
}
debug_out_info("app", "Device " << get_device_with_type() << " detected after parser to be of type "
<< StorageDeviceDetectedTypeExt::get_storable_name(get_detected_type()) << "\n");
}