From 9b0b6b7555cc85365f266412a1b3d27f6e5342c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Matar=C3=A9?= Date: Fri, 7 Apr 2023 18:16:47 +0200 Subject: [PATCH 1/6] hwmon: refactor & support lookup of all indices This should allow the user to omit the indices: config field if a sensor input is sufficiently specified by other criteria. In this case, thinkfan should pick up all pwm/temp files found for the given sensor. A major caveat being that the number of available temperature inputs won't be known before a sensors has been successfully looked up... --- src/hwmon.cpp | 88 ++++++++++++++++++++++++++++++++------------------- src/hwmon.h | 2 ++ 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/src/hwmon.cpp b/src/hwmon.cpp index c3bb65d..d0940d2 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -29,14 +29,17 @@ #include #include #include +#include namespace thinkfan { +namespace filesystem = std::filesystem; + static int filter_hwmon_dirs(const struct dirent *entry) { return (entry->d_type == DT_DIR || entry->d_type == DT_LNK) - && (!strncmp("hwmon", entry->d_name, 5) || !strcmp("device", entry->d_name)); + && (string(entry->d_name) == "hwmon" || string(entry->d_name) == "device"); } @@ -48,6 +51,43 @@ static int filter_subdirs(const struct dirent *entry) } +template<> +int HwmonInterface::filter_driver_file(const struct dirent *entry) +{ + int idx; + return (entry->d_type == DT_REG || entry->d_type == DT_LNK) + && !::sscanf(entry->d_name, "temp%d_input", &idx) + ; +} + +template<> +int HwmonInterface::filter_driver_file(const struct dirent *entry) +{ + int idx; + return (entry->d_type == DT_REG || entry->d_type == DT_LNK) + && !::sscanf(entry->d_name, "pwm%d", &idx) + ; +} + + +template +vector dir_entries(const filesystem::path &dir) +{ + struct dirent **entries; + int nentries = ::scandir(dir.c_str(), &entries, filter_fn, nullptr); + if (nentries == -1) + return {}; + + vector rv; + for (int i = 0; i < nentries; ++i) { + rv.emplace_back(dir / entries[i]->d_name); + ::free(entries[i]); + } + ::free(entries); + return rv; +} + + template vector HwmonInterface::find_files(const string &path, const vector &indices) { @@ -85,6 +125,7 @@ HwmonInterface::HwmonInterface(const string &base_path, opt vector HwmonInterface::find_hwmons_by_name( const string &path, @@ -106,15 +147,7 @@ vector HwmonInterface::find_hwmons_by_name( return result; // don't recurse to subdirs } - struct dirent **entries; - int nentries = ::scandir(path.c_str(), &entries, filter_subdirs, nullptr); - if (nentries == -1) { - return result; - } - for (int i = 0; i < nentries; i++) { - auto subdir = path + "/" + entries[i]->d_name; - free(entries[i]); - + for (const filesystem::path &subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -123,11 +156,11 @@ vector HwmonInterface::find_hwmons_by_name( auto found = find_hwmons_by_name(subdir, name, depth + 1); result.insert(result.end(), found.begin(), found.end()); } - free(entries); return result; } + template vector HwmonInterface::find_hwmons_by_model( const string &path, @@ -152,15 +185,7 @@ vector HwmonInterface::find_hwmons_by_model( return result; // don't recurse to subdirs } - struct dirent **entries; - int nentries = ::scandir(path.c_str(), &entries, filter_subdirs, nullptr); - if (nentries == -1) { - return result; - } - for (int i = 0; i < nentries; i++) { - auto subdir = path + "/" + entries[i]->d_name; - free(entries[i]); - + for (const filesystem::path &subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -169,11 +194,11 @@ vector HwmonInterface::find_hwmons_by_model( auto found = find_hwmons_by_model(subdir, model, depth + 1); result.insert(result.end(), found.begin(), found.end()); } - free(entries); return result; } + template vector HwmonInterface::find_hwmons_by_indices( const string &path, @@ -187,24 +212,20 @@ vector HwmonInterface::find_hwmons_by_indices( } catch (IOerror &) { if (depth <= max_depth) { - struct dirent **entries; - int nentries = ::scandir(path.c_str(), &entries, filter_hwmon_dirs, alphasort); - if (nentries < 0) + vector hwmon_dirs = dir_entries(path); + if (hwmon_dirs.empty()) throw IOerror("Error scanning " + path + ": ", errno); vector rv; - for (int i = 0; i < nentries; i++) { + for (const filesystem::path &hwmon_dir : hwmon_dirs) { rv = HwmonInterface::find_hwmons_by_indices( - path + "/" + entries[i]->d_name, + hwmon_dir, indices, depth + 1 ); if (rv.size()) break; } - for (int i = 0; i < nentries; i++) - free(entries[i]); - free(entries); return rv; } @@ -214,7 +235,6 @@ vector HwmonInterface::find_hwmons_by_indices( } - template string HwmonInterface::lookup() { @@ -229,7 +249,7 @@ string HwmonInterface::lookup() if (paths.size() != 1) { string msg(path + ": "); if (paths.size() == 0) { - msg += "Could not find a hwmon with this name: " + name_.value(); + msg += "Could not find an hwmon with this name: " + name_.value(); } else { msg += MSG_MULTIPLE_HWMONS_FOUND; for (string hwmon_path : paths) @@ -259,8 +279,10 @@ string HwmonInterface::lookup() if (found_paths_.size() == 0) throw DriverInitError(path + ": " + "Could not find any hwmons in " + path); } - else - found_paths_.push_back(path); + else { + vector paths = dir_entries(path); + found_paths_.assign(paths.begin(), paths.end()); + } paths_it_.emplace(found_paths_.begin()); } diff --git a/src/hwmon.h b/src/hwmon.h index 92e3b1f..119f017 100644 --- a/src/hwmon.h +++ b/src/hwmon.h @@ -41,6 +41,7 @@ class HwmonInterface { string lookup(); private: + static int filter_driver_file(const struct dirent *entry); static vector find_files(const string &path, const vector &indices); static string filename(unsigned int index); @@ -48,6 +49,7 @@ class HwmonInterface { static vector find_hwmons_by_name(const string &path, const string &name, unsigned char depth); static vector find_hwmons_by_indices(const string &path, const vector &indices, unsigned char depth); + protected: opt base_path_; opt name_; From e5d0e82aac8436ee86feb2de90635ba189ebbd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Matar=C3=A9?= Date: Wed, 16 Oct 2024 15:55:59 +0200 Subject: [PATCH 2/6] hwmon: use vector::swap instead of assign Co-authored-by: zotnhucucbot --- src/hwmon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hwmon.cpp b/src/hwmon.cpp index d0940d2..893f8f9 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -281,7 +281,7 @@ string HwmonInterface::lookup() } else { vector paths = dir_entries(path); - found_paths_.assign(paths.begin(), paths.end()); + found_paths_.swap(paths); } paths_it_.emplace(found_paths_.begin()); From a98b7738053172140a4385aa089f3e9a03fba834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Matar=C3=A9?= Date: Wed, 16 Oct 2024 16:08:42 +0200 Subject: [PATCH 3/6] hwmon: fix fs:path vs string punning --- src/hwmon.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hwmon.cpp b/src/hwmon.cpp index 893f8f9..ed1bd7e 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -71,14 +71,14 @@ int HwmonInterface::filter_driver_file(const struct dirent *entry) template -vector dir_entries(const filesystem::path &dir) +vector dir_entries(const filesystem::path &dir) { struct dirent **entries; int nentries = ::scandir(dir.c_str(), &entries, filter_fn, nullptr); if (nentries == -1) return {}; - vector rv; + vector rv; for (int i = 0; i < nentries; ++i) { rv.emplace_back(dir / entries[i]->d_name); ::free(entries[i]); @@ -212,12 +212,12 @@ vector HwmonInterface::find_hwmons_by_indices( } catch (IOerror &) { if (depth <= max_depth) { - vector hwmon_dirs = dir_entries(path); + vector hwmon_dirs = dir_entries(path); if (hwmon_dirs.empty()) throw IOerror("Error scanning " + path + ": ", errno); vector rv; - for (const filesystem::path &hwmon_dir : hwmon_dirs) { + for (const filesystem::path hwmon_dir : hwmon_dirs) { rv = HwmonInterface::find_hwmons_by_indices( hwmon_dir, indices, @@ -280,7 +280,7 @@ string HwmonInterface::lookup() throw DriverInitError(path + ": " + "Could not find any hwmons in " + path); } else { - vector paths = dir_entries(path); + vector paths = dir_entries(path); found_paths_.swap(paths); } From 701589697e8f82c8274d02497a14811732eb1d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Matar=C3=A9?= Date: Thu, 17 Oct 2024 01:45:16 +0200 Subject: [PATCH 4/6] hwmon: fix sscanf retval check --- src/hwmon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hwmon.cpp b/src/hwmon.cpp index ed1bd7e..4e5d2c9 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -56,7 +56,7 @@ int HwmonInterface::filter_driver_file(const struct dirent *entry) { int idx; return (entry->d_type == DT_REG || entry->d_type == DT_LNK) - && !::sscanf(entry->d_name, "temp%d_input", &idx) + && ::sscanf(entry->d_name, "temp%d_input", &idx) == 1 ; } @@ -65,7 +65,7 @@ int HwmonInterface::filter_driver_file(const struct dirent *entry) { int idx; return (entry->d_type == DT_REG || entry->d_type == DT_LNK) - && !::sscanf(entry->d_name, "pwm%d", &idx) + && ::sscanf(entry->d_name, "pwm%d", &idx) == 1 ; } From b27058a380f346f26c248ff7ca93f940256ab18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Matar=C3=A9?= Date: Thu, 17 Oct 2024 01:45:36 +0200 Subject: [PATCH 5/6] fix string/fs:path conversion --- src/hwmon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hwmon.cpp b/src/hwmon.cpp index 4e5d2c9..16a2386 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -147,7 +147,7 @@ vector HwmonInterface::find_hwmons_by_name( return result; // don't recurse to subdirs } - for (const filesystem::path &subdir : dir_entries(path)) { + for (const filesystem::path subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -185,7 +185,7 @@ vector HwmonInterface::find_hwmons_by_model( return result; // don't recurse to subdirs } - for (const filesystem::path &subdir : dir_entries(path)) { + for (const filesystem::path subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) From f1fdb07f04cba96b48e7114f746fe5837e145e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Matar=C3=A9?= Date: Sun, 20 Oct 2024 22:14:00 +0200 Subject: [PATCH 6/6] WIP --- src/hwmon.cpp | 76 ++++++++++++++++++++++++++------------------------- src/hwmon.h | 13 +++++---- src/message.h | 26 ++++++++++++++++++ 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/hwmon.cpp b/src/hwmon.cpp index 16a2386..481e9e0 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -29,11 +29,9 @@ #include #include #include -#include namespace thinkfan { -namespace filesystem = std::filesystem; static int filter_hwmon_dirs(const struct dirent *entry) @@ -88,29 +86,23 @@ vector dir_entries(const filesystem::path &dir) } -template -vector HwmonInterface::find_files(const string &path, const vector &indices) -{ - vector rv; - for (unsigned int idx : indices) { - const string fpath(path + "/" + filename(idx)); - std::ifstream f(fpath); - if (f.is_open() && f.good()) - rv.push_back(fpath); - else - throw IOerror("Can't find hwmon file: " + fpath, errno); - } - return rv; -} +template<> +string HwmonInterface::filename_by_index(unsigned int index) +{ return "pwm" + std::to_string(index); } template<> -string HwmonInterface::filename(unsigned int index) +string HwmonInterface::filename_by_index(unsigned int index) { return "temp" + std::to_string(index) + "_input"; } -template<> -string HwmonInterface::filename(unsigned int index) -{ return "pwm" + std::to_string(index); } +template +vector HwmonInterface::filenames_by_indices(const vector &indices) +{ + vector rv; + for (unsigned int index : indices) + rv.push_back(filename_by_index(index)); + return rv; +} template @@ -128,14 +120,14 @@ HwmonInterface::HwmonInterface(const string &base_path, opt vector HwmonInterface::find_hwmons_by_name( - const string &path, + const filesystem::path &path, const string &name, unsigned char depth ) { const unsigned char max_depth = 5; vector result; - ifstream f(path + "/name"); + ifstream f(path / "name"); if (f.is_open() && f.good()) { string tmp; if ((f >> tmp) && tmp == name) { @@ -147,7 +139,7 @@ vector HwmonInterface::find_hwmons_by_name( return result; // don't recurse to subdirs } - for (const filesystem::path subdir : dir_entries(path)) { + for (const auto &subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -163,14 +155,14 @@ vector HwmonInterface::find_hwmons_by_name( template vector HwmonInterface::find_hwmons_by_model( - const string &path, + const filesystem::path &path, const string &model, unsigned char depth ) { const unsigned char max_depth = 5; vector result; - ifstream f(path + "/model"); + ifstream f(path / "model"); if (f.is_open() && f.good()) { string tmp; if (getline(f, tmp)) { @@ -185,7 +177,7 @@ vector HwmonInterface::find_hwmons_by_model( return result; // don't recurse to subdirs } - for (const filesystem::path subdir : dir_entries(path)) { + for (const auto &subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -201,37 +193,47 @@ vector HwmonInterface::find_hwmons_by_model( template vector HwmonInterface::find_hwmons_by_indices( - const string &path, + const filesystem::path &path, const vector &indices, unsigned char depth ) { constexpr unsigned char max_depth = 3; - try { - return find_files(path, indices); + vector rv; + vector filenames = filenames_by_indices(indices); + for (const filesystem::path fname : filenames) { + const filesystem::path fpath(path / fname); + std::ifstream f(fpath); + if (f.is_open() && f.good()) + rv.push_back(fpath); + else if (rv.size()) // Found one, but another is missing: Error + throw IOerror("Can't find hwmon file: " + string(fpath), errno); } - catch (IOerror &) { + + if (rv.empty()) { // No matching files in this directory if (depth <= max_depth) { vector hwmon_dirs = dir_entries(path); if (hwmon_dirs.empty()) - throw IOerror("Error scanning " + path + ": ", errno); + return {}; - vector rv; - for (const filesystem::path hwmon_dir : hwmon_dirs) { + for (const auto &hwmon_dir : hwmon_dirs) { rv = HwmonInterface::find_hwmons_by_indices( hwmon_dir, indices, depth + 1 ); if (rv.size()) - break; + return rv; } - return rv; + if (depth == 0) // Nothing found here or after recursion + throw DriverInitError( + "Could not find requested files " + vec_to_string(filenames) + + " in " + string(path) + "." + ); } - else - throw DriverInitError("Could not find an `hwmon*' directory or `temp*_input' file in " + path + "."); } + return rv; } diff --git a/src/hwmon.h b/src/hwmon.h index 119f017..fc7e64b 100644 --- a/src/hwmon.h +++ b/src/hwmon.h @@ -24,6 +24,7 @@ #include "thinkfan.h" #include +#include namespace thinkfan { @@ -31,6 +32,8 @@ namespace thinkfan { class HwmonSensorDriver; class HwmonFanDriver; +namespace filesystem = std::filesystem; + template class HwmonInterface { @@ -42,12 +45,12 @@ class HwmonInterface { private: static int filter_driver_file(const struct dirent *entry); - static vector find_files(const string &path, const vector &indices); - static string filename(unsigned int index); + static string filename_by_index(unsigned int index); + static vector filenames_by_indices(const vector &indices); - static vector find_hwmons_by_model(const string &path, const string &model, unsigned char depth); - static vector find_hwmons_by_name(const string &path, const string &name, unsigned char depth); - static vector find_hwmons_by_indices(const string &path, const vector &indices, unsigned char depth); + static vector find_hwmons_by_model(const filesystem::path &path, const string &model, unsigned char depth); + static vector find_hwmons_by_name(const filesystem::path &path, const string &name, unsigned char depth); + static vector find_hwmons_by_indices(const filesystem::path &path, const vector &indices, unsigned char depth); protected: diff --git a/src/message.h b/src/message.h index df61ba8..99a4625 100644 --- a/src/message.h +++ b/src/message.h @@ -106,6 +106,32 @@ template void error(const ArgTs &... args) { } +template +string to_string(const T &); + + +template<> +string to_string(const string &s) +{ return s; } + +template +string to_string(const T &o) +{ return std::to_string(o); } + + +template +string vec_to_string(const vector &v) +{ + string rv = "["; + for (const T& item : v) + rv += to_string(item) + ", "; + if (rv.length() > 2) + rv = rv.substr(0, rv.length() - 2); + rv += "]"; + return rv; +} + + } // namespace thinkfan