mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-27 14:25:34 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e848aa3fa0 | ||
|
|
9692c78944 | ||
|
|
6fba7765f7 |
@@ -115,6 +115,7 @@ bool storage_property_autoset_description(StorageProperty& p, StorageDeviceDetec
|
||||
found = auto_set(p, "ata_smart_attributes/revision", p.displayable_name.c_str());
|
||||
if (!found) {
|
||||
auto_set_ata_attribute_description(p, device_type);
|
||||
storage_property_ata_attribute_humanize_ssd_writes(p);
|
||||
found = true; // true, because auto_set_attr() may set "Unknown attribute", which is still "found".
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,6 +22,7 @@ Copyright:
|
||||
//#include "warning_colors.h"
|
||||
#include "storage_property_descr_helpers.h"
|
||||
#include "hz/string_num.h"
|
||||
#include "hz/format_unit.h" // format_size
|
||||
|
||||
|
||||
namespace {
|
||||
@@ -1364,5 +1365,104 @@ void storage_property_ata_attribute_autoset_warning(StorageProperty& p)
|
||||
|
||||
|
||||
|
||||
void storage_property_ata_attribute_humanize_ssd_writes(StorageProperty& p)
|
||||
{
|
||||
if (p.section != StoragePropertySection::AtaAttributes || !p.is_value_type<AtaStorageAttribute>()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& attr = p.get_value<AtaStorageAttribute>();
|
||||
|
||||
// Skip if readable_value is already set (e.g., by parser or for GiB attributes)
|
||||
if (!p.readable_value.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Standard sector size (512 bytes)
|
||||
constexpr uint64_t bytes_per_sector = 512;
|
||||
constexpr uint64_t mib_32 = 32ULL * 1024ULL * 1024ULL;
|
||||
constexpr uint64_t gib = 1024ULL * 1024ULL * 1024ULL;
|
||||
|
||||
// Match attribute by ID and reported name to handle vendor-specific attributes
|
||||
const int32_t id = attr.id;
|
||||
const std::string& name = p.reported_name;
|
||||
std::optional<uint64_t> bytes;
|
||||
|
||||
// Write attributes - these need humanization most
|
||||
// Attribute 199: Write_Sectors_Tot_Ct (Indilinx Barefoot SSDs)
|
||||
// Total count of written sectors
|
||||
if (id == 199 && name == "Write_Sectors_Tot_Ct") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * bytes_per_sector;
|
||||
}
|
||||
// Attribute 225: Host_Writes_32MiB (Intel SSDs)
|
||||
else if (id == 225 && name == "Host_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 241: Host_Writes_32MiB (various SSDs)
|
||||
// Raw value increased by 1 for every 32 MiB written
|
||||
else if (id == 241 && name == "Host_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 243: Host_Writes_32MiB (SanDisk SSDs)
|
||||
else if (id == 243 && name == "Host_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 245: Flash_Writes_32MiB (Innodisk SSDs)
|
||||
else if (id == 245 && name == "Flash_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 245: TLC_Writes_32MiB (SiliconMotion SSDs)
|
||||
else if (id == 245 && name == "TLC_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 246: SLC_Writes_32MiB (SiliconMotion SSDs)
|
||||
else if (id == 246 && name == "SLC_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 246: Total_Host_Sector_Write (Crucial/Micron SSDs)
|
||||
// Total number of sectors written by the host system
|
||||
else if (id == 246 && name == "Total_Host_Sector_Write") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * bytes_per_sector;
|
||||
}
|
||||
// Attribute 249: NAND_Writes_1GiB (Intel SSDs)
|
||||
// Note: The raw value is the count, not already in GiB
|
||||
else if (id == 249 && name == "NAND_Writes_1GiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * gib;
|
||||
}
|
||||
// Attribute 249: Total_NAND_Prog_Ct_GiB (OCZ SSDs)
|
||||
else if (id == 249 && name == "Total_NAND_Prog_Ct_GiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * gib;
|
||||
}
|
||||
|
||||
// Read attributes - also humanize for consistency
|
||||
// Attribute 198: Read_Sectors_Tot_Ct (Indilinx Barefoot SSDs)
|
||||
else if (id == 198 && name == "Read_Sectors_Tot_Ct") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * bytes_per_sector;
|
||||
}
|
||||
// Attribute 226: Host_Reads_32MiB (Intel SSDs)
|
||||
else if (id == 226 && name == "Host_Reads_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 242: Host_Reads_32MiB (Intel SSDs)
|
||||
else if (id == 242 && name == "Host_Reads_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 244: Flash_Reads_32MiB (Innodisk SSDs)
|
||||
else if (id == 244 && name == "Flash_Reads_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 251: Total_NAND_Read_Ct_GiB (OCZ SSDs)
|
||||
else if (id == 251 && name == "Total_NAND_Read_Ct_GiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * gib;
|
||||
}
|
||||
|
||||
// Set readable_value if we determined the byte count
|
||||
if (bytes.has_value() && bytes.value() > 0) {
|
||||
// Use binary units (KiB, MiB, GiB, TiB) for consistency with existing attributes
|
||||
p.readable_value = hz::format_size(bytes.value(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -26,6 +26,11 @@ void auto_set_ata_attribute_description(StorageProperty& p, StorageDeviceDetecte
|
||||
void storage_property_ata_attribute_autoset_warning(StorageProperty& p);
|
||||
|
||||
|
||||
/// Humanize SSD write statistics by converting raw values to readable byte counts.
|
||||
/// Sets the readable_value field for applicable write-related attributes.
|
||||
void storage_property_ata_attribute_humanize_ssd_writes(StorageProperty& p);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
|
||||
+3
-116
@@ -21,11 +21,6 @@ Copyright:
|
||||
#include "win32_tools.h" // hz::win32_utf8_to_utf16
|
||||
#else
|
||||
#include <memory>
|
||||
#include <unistd.h> // geteuid, fork, execvp, setuid, setgid
|
||||
#include <sys/types.h> // uid_t, gid_t
|
||||
#include <sys/wait.h> // waitpid
|
||||
#include <pwd.h> // getpwuid
|
||||
#include "env_tools.h" // hz::env_get_value
|
||||
#endif
|
||||
|
||||
|
||||
@@ -34,89 +29,6 @@ Copyright:
|
||||
namespace hz {
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/// Launch URL as the original user when running as root.
|
||||
/// This is needed because gtk_show_uri_on_window() doesn't work when running as root
|
||||
/// (D-Bus session is not accessible).
|
||||
/// \return error message on error, empty string on success.
|
||||
inline std::string launch_url_as_original_user(const std::string& link)
|
||||
{
|
||||
// Get the original user's UID from environment variables
|
||||
// SUDO_UID is set by sudo, PKEXEC_UID is set by pkexec
|
||||
std::string uid_str;
|
||||
uid_t original_uid = 0;
|
||||
gid_t original_gid = 0;
|
||||
|
||||
if (hz::env_get_value("SUDO_UID", uid_str) || hz::env_get_value("PKEXEC_UID", uid_str)) {
|
||||
try {
|
||||
original_uid = static_cast<uid_t>(std::stoul(uid_str));
|
||||
} catch (...) {
|
||||
return "Cannot parse original user UID";
|
||||
}
|
||||
|
||||
// Get the original user's GID
|
||||
struct passwd* pw = getpwuid(original_uid);
|
||||
if (pw) {
|
||||
original_gid = pw->pw_gid;
|
||||
} else {
|
||||
return "Cannot get original user information";
|
||||
}
|
||||
} else {
|
||||
return "Cannot determine original user UID";
|
||||
}
|
||||
|
||||
// Fork and execute xdg-open as the original user
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
return "Cannot fork process";
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// Child process
|
||||
|
||||
// Restore HOME environment variable if available
|
||||
// This helps xdg-open find the correct configuration
|
||||
std::string sudo_user;
|
||||
if (hz::env_get_value("SUDO_USER", sudo_user)) {
|
||||
struct passwd* pw = getpwnam(sudo_user.c_str());
|
||||
if (pw && pw->pw_dir) {
|
||||
setenv("HOME", pw->pw_dir, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop privileges to original user
|
||||
// Set GID first, then UID (order matters for security)
|
||||
if (setgid(original_gid) != 0) {
|
||||
_exit(1);
|
||||
}
|
||||
if (setuid(original_uid) != 0) {
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Execute xdg-open with the URL
|
||||
const char* argv[] = {"xdg-open", link.c_str(), nullptr};
|
||||
execvp("xdg-open", const_cast<char* const*>(argv));
|
||||
|
||||
// If execvp returns, it failed
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Parent process - wait for child
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
return "Cannot wait for child process";
|
||||
}
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||
return {}; // Success
|
||||
}
|
||||
|
||||
return "xdg-open failed to launch URL";
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
/// Open URL in browser or mailto: link in mail client.
|
||||
/// Return error message on error, empty string otherwise.
|
||||
@@ -138,41 +50,16 @@ inline std::string launch_url([[maybe_unused]] GtkWindow* window, const std::str
|
||||
#else
|
||||
|
||||
GError* error = nullptr;
|
||||
bool status = false;
|
||||
|
||||
// Check if running as root
|
||||
bool is_root = (geteuid() == 0);
|
||||
|
||||
// If running as root, try to launch as the original user first
|
||||
if (is_root) {
|
||||
std::string result = launch_url_as_original_user(link);
|
||||
if (result.empty()) {
|
||||
return {}; // Success
|
||||
}
|
||||
// If launching as original user failed, fall through to try GTK method
|
||||
}
|
||||
|
||||
// Try the standard GTK method
|
||||
#if GTK_CHECK_VERSION(3, 22, 0)
|
||||
status = static_cast<bool>(gtk_show_uri_on_window(window, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
bool status = static_cast<bool>(gtk_show_uri_on_window(window, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
#else
|
||||
GdkScreen* screen = (window ? gtk_window_get_screen(window) : nullptr);
|
||||
status = static_cast<bool>(gtk_show_uri(screen, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
bool status = static_cast<bool>(gtk_show_uri(screen, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
#endif
|
||||
std::unique_ptr<GError, decltype(&g_error_free)> uerror(error, &g_error_free);
|
||||
|
||||
if (!status) {
|
||||
// GTK method failed. If running as root, we already tried the fallback.
|
||||
// Otherwise, try the fallback now.
|
||||
if (!is_root) {
|
||||
std::string result = launch_url_as_original_user(link);
|
||||
if (result.empty()) {
|
||||
return {}; // Success
|
||||
}
|
||||
}
|
||||
|
||||
// Both methods failed, return error
|
||||
return std::string("Cannot open URL")
|
||||
return std::string("Cannot open URL: ")
|
||||
+ ((error && error->message) ? (std::string(": ") + error->message) : ".");
|
||||
}
|
||||
return {};
|
||||
|
||||
Reference in New Issue
Block a user