1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright 2017 Intel Corporation 3 4 #include "utils.hpp" 5 6 #include <boost/algorithm/string/replace.hpp> 7 #include <boost/container/flat_map.hpp> 8 #include <boost/lexical_cast.hpp> 9 #include <phosphor-logging/lg2.hpp> 10 #include <sdbusplus/bus/match.hpp> 11 12 #include <algorithm> 13 #include <cctype> 14 #include <filesystem> 15 #include <map> 16 #include <ranges> 17 #include <regex> 18 #include <string_view> 19 #include <utility> 20 21 namespace fs = std::filesystem; 22 23 bool findFiles(const fs::path& dirPath, const std::string& matchString, 24 std::vector<fs::path>& foundPaths) 25 { 26 if (!fs::exists(dirPath)) 27 { 28 return false; 29 } 30 31 std::regex search(matchString); 32 std::smatch match; 33 for (const auto& p : fs::directory_iterator(dirPath)) 34 { 35 std::string path = p.path().string(); 36 if (std::regex_search(path, match, search)) 37 { 38 foundPaths.emplace_back(p.path()); 39 } 40 } 41 return true; 42 } 43 44 bool findFiles(const std::vector<fs::path>&& dirPaths, 45 const std::string& matchString, 46 std::vector<fs::path>& foundPaths) 47 { 48 std::map<fs::path, fs::path> paths; 49 std::regex search(matchString); 50 std::smatch match; 51 for (const auto& dirPath : dirPaths) 52 { 53 if (!fs::exists(dirPath)) 54 { 55 continue; 56 } 57 58 for (const auto& p : fs::recursive_directory_iterator(dirPath)) 59 { 60 std::error_code ec; 61 if (p.is_directory(ec)) 62 { 63 continue; 64 } 65 66 std::string path = p.path().string(); 67 if (std::regex_search(path, match, search)) 68 { 69 paths[p.path().filename()] = p.path(); 70 } 71 } 72 } 73 74 for (const auto& [key, value] : paths) 75 { 76 foundPaths.emplace_back(value); 77 } 78 79 return !foundPaths.empty(); 80 } 81 82 bool getI2cDevicePaths(const fs::path& dirPath, 83 boost::container::flat_map<size_t, fs::path>& busPaths) 84 { 85 if (!fs::exists(dirPath)) 86 { 87 return false; 88 } 89 90 // Regex for matching the path 91 std::regex searchPath(std::string(R"(i2c-\d+$)")); 92 // Regex for matching the bus numbers 93 std::regex searchBus(std::string(R"(\w[^-]*$)")); 94 std::smatch matchPath; 95 std::smatch matchBus; 96 for (const auto& p : fs::directory_iterator(dirPath)) 97 { 98 std::string path = p.path().string(); 99 if (std::regex_search(path, matchPath, searchPath)) 100 { 101 if (std::regex_search(path, matchBus, searchBus)) 102 { 103 size_t bus = stoul(*matchBus.begin()); 104 busPaths.insert(std::pair<size_t, fs::path>(bus, p.path())); 105 } 106 } 107 } 108 109 return true; 110 } 111 112 /// \brief JSON/DBus matching Callable for std::variant (visitor) 113 /// 114 /// Default match JSON/DBus match implementation 115 /// \tparam T The concrete DBus value type from DBusValueVariant 116 template <typename T> 117 struct MatchProbe 118 { 119 /// \param probe the probe statement to match against 120 /// \param value the property value being matched to a probe 121 /// \return true if the dbusValue matched the probe otherwise false 122 static bool match(const nlohmann::json& probe, const T& value) 123 { 124 return probe == value; 125 } 126 }; 127 128 /// \brief JSON/DBus matching Callable for std::variant (visitor) 129 /// 130 /// std::string specialization of MatchProbe enabling regex matching 131 template <> 132 struct MatchProbe<std::string> 133 { 134 /// \param probe the probe statement to match against 135 /// \param value the string value being matched to a probe 136 /// \return true if the dbusValue matched the probe otherwise false 137 static bool match(const nlohmann::json& probe, const std::string& value) 138 { 139 if (probe.is_string()) 140 { 141 try 142 { 143 std::regex search(probe); 144 std::smatch regMatch; 145 return std::regex_search(value, regMatch, search); 146 } 147 catch (const std::regex_error&) 148 { 149 lg2::error( 150 "Syntax error in regular expression: {PROBE} will never match", 151 "PROBE", probe); 152 } 153 } 154 155 // Skip calling nlohmann here, since it will never match a non-string 156 // to a std::string 157 return false; 158 } 159 }; 160 161 /// \brief Forwarding JSON/DBus matching Callable for std::variant (visitor) 162 /// 163 /// Forward calls to the correct template instantiation of MatchProbe 164 struct MatchProbeForwarder 165 { 166 explicit MatchProbeForwarder(const nlohmann::json& probe) : probeRef(probe) 167 {} 168 const nlohmann::json& probeRef; 169 170 template <typename T> 171 bool operator()(const T& dbusValue) const 172 { 173 return MatchProbe<T>::match(probeRef, dbusValue); 174 } 175 }; 176 177 bool matchProbe(const nlohmann::json& probe, const DBusValueVariant& dbusValue) 178 { 179 return std::visit(MatchProbeForwarder(probe), dbusValue); 180 } 181 182 std::vector<std::string> split(std::string_view str, char delim) 183 { 184 std::vector<std::string> out; 185 186 size_t start = 0; 187 while (start <= str.size()) 188 { 189 size_t end = str.find(delim, start); 190 if (end == std::string_view::npos) 191 { 192 out.emplace_back(str.substr(start)); 193 break; 194 } 195 196 out.emplace_back(str.substr(start, end - start)); 197 start = end + 1; 198 } 199 200 return out; 201 } 202