diff --git a/src/hwmon.cpp b/src/hwmon.cpp index c3bb65d..481e9e0 100644 --- a/src/hwmon.cpp +++ b/src/hwmon.cpp @@ -33,10 +33,11 @@ namespace thinkfan { + 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,29 +49,60 @@ static int filter_subdirs(const struct dirent *entry) } -template -vector HwmonInterface::find_files(const string &path, const vector &indices) +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) == 1 + ; +} + +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) == 1 + ; +} + + +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 (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); + for (int i = 0; i < nentries; ++i) { + rv.emplace_back(dir / entries[i]->d_name); + ::free(entries[i]); } + ::free(entries); return rv; } -template<> -string HwmonInterface::filename(unsigned int index) -{ return "temp" + std::to_string(index) + "_input"; } template<> -string HwmonInterface::filename(unsigned int index) +string HwmonInterface::filename_by_index(unsigned int index) { return "pwm" + std::to_string(index); } +template<> +string HwmonInterface::filename_by_index(unsigned int index) +{ return "temp" + std::to_string(index) + "_input"; } + + +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 @@ -85,16 +117,17 @@ 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) { @@ -106,15 +139,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 auto &subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -123,21 +148,21 @@ 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, + 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)) { @@ -152,15 +177,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 auto &subdir : dir_entries(path)) { struct stat statbuf; int err = stat(path.c_str(), &statbuf); if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR) @@ -169,52 +186,57 @@ 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, + 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) { - struct dirent **entries; - int nentries = ::scandir(path.c_str(), &entries, filter_hwmon_dirs, alphasort); - if (nentries < 0) - throw IOerror("Error scanning " + path + ": ", errno); + vector hwmon_dirs = dir_entries(path); + if (hwmon_dirs.empty()) + return {}; - vector rv; - for (int i = 0; i < nentries; i++) { + for (const auto &hwmon_dir : hwmon_dirs) { rv = HwmonInterface::find_hwmons_by_indices( - path + "/" + entries[i]->d_name, + hwmon_dir, indices, depth + 1 ); if (rv.size()) - break; + return rv; } - for (int i = 0; i < nentries; i++) - free(entries[i]); - free(entries); - 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; } - template string HwmonInterface::lookup() { @@ -229,7 +251,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 +281,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_.swap(paths); + } paths_it_.emplace(found_paths_.begin()); } diff --git a/src/hwmon.h b/src/hwmon.h index 92e3b1f..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 { @@ -41,12 +44,14 @@ class HwmonInterface { string lookup(); private: - static vector find_files(const string &path, const vector &indices); - static string filename(unsigned int index); + static int filter_driver_file(const struct dirent *entry); + static string filename_by_index(unsigned int index); + static vector filenames_by_indices(const vector &indices); + + 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); - 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); protected: opt base_path_; 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