xref: /openbmc/entity-manager/src/utils.cpp (revision ecf1a31636a65f3eb2aaa7e45c8b51b900bedf7b)
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