xref: /openbmc/entity-manager/src/utils.cpp (revision d8e86039f401391556fd230a1e0f249d921ebf60)
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 /// \file utils.cpp
17 
18 #include "utils.hpp"
19 
20 #include <boost/algorithm/string/classification.hpp>
21 #include <boost/algorithm/string/find.hpp>
22 #include <boost/algorithm/string/predicate.hpp>
23 #include <boost/algorithm/string/replace.hpp>
24 #include <boost/algorithm/string/split.hpp>
25 #include <boost/container/flat_map.hpp>
26 #include <boost/lexical_cast.hpp>
27 #include <sdbusplus/bus/match.hpp>
28 
29 #include <filesystem>
30 #include <iostream>
31 #include <map>
32 #include <regex>
33 
34 namespace fs = std::filesystem;
35 
findFiles(const fs::path & dirPath,const std::string & matchString,std::vector<fs::path> & foundPaths)36 bool findFiles(const fs::path& dirPath, const std::string& matchString,
37                std::vector<fs::path>& foundPaths)
38 {
39     if (!fs::exists(dirPath))
40     {
41         return false;
42     }
43 
44     std::regex search(matchString);
45     std::smatch match;
46     for (const auto& p : fs::directory_iterator(dirPath))
47     {
48         std::string path = p.path().string();
49         if (std::regex_search(path, match, search))
50         {
51             foundPaths.emplace_back(p.path());
52         }
53     }
54     return true;
55 }
56 
findFiles(const std::vector<fs::path> && dirPaths,const std::string & matchString,std::vector<fs::path> & foundPaths)57 bool findFiles(const std::vector<fs::path>&& dirPaths,
58                const std::string& matchString,
59                std::vector<fs::path>& foundPaths)
60 {
61     std::map<fs::path, fs::path> paths;
62     std::regex search(matchString);
63     std::smatch match;
64     for (const auto& dirPath : dirPaths)
65     {
66         if (!fs::exists(dirPath))
67         {
68             continue;
69         }
70 
71         for (const auto& p : fs::recursive_directory_iterator(dirPath))
72         {
73             std::error_code ec;
74             if (p.is_directory(ec))
75             {
76                 continue;
77             }
78 
79             std::string path = p.path().string();
80             if (std::regex_search(path, match, search))
81             {
82                 paths[p.path().filename()] = p.path();
83             }
84         }
85     }
86 
87     for (const auto& [key, value] : paths)
88     {
89         foundPaths.emplace_back(value);
90     }
91 
92     return !foundPaths.empty();
93 }
94 
getI2cDevicePaths(const fs::path & dirPath,boost::container::flat_map<size_t,fs::path> & busPaths)95 bool getI2cDevicePaths(const fs::path& dirPath,
96                        boost::container::flat_map<size_t, fs::path>& busPaths)
97 {
98     if (!fs::exists(dirPath))
99     {
100         return false;
101     }
102 
103     // Regex for matching the path
104     std::regex searchPath(std::string(R"(i2c-\d+$)"));
105     // Regex for matching the bus numbers
106     std::regex searchBus(std::string(R"(\w[^-]*$)"));
107     std::smatch matchPath;
108     std::smatch matchBus;
109     for (const auto& p : fs::directory_iterator(dirPath))
110     {
111         std::string path = p.path().string();
112         if (std::regex_search(path, matchPath, searchPath))
113         {
114             if (std::regex_search(path, matchBus, searchBus))
115             {
116                 size_t bus = stoul(*matchBus.begin());
117                 busPaths.insert(std::pair<size_t, fs::path>(bus, p.path()));
118             }
119         }
120     }
121 
122     return true;
123 }
124 
125 /// \brief JSON/DBus matching Callable for std::variant (visitor)
126 ///
127 /// Default match JSON/DBus match implementation
128 /// \tparam T The concrete DBus value type from DBusValueVariant
129 template <typename T>
130 struct MatchProbe
131 {
132     /// \param probe the probe statement to match against
133     /// \param value the property value being matched to a probe
134     /// \return true if the dbusValue matched the probe otherwise false
matchMatchProbe135     static bool match(const nlohmann::json& probe, const T& value)
136     {
137         return probe == value;
138     }
139 };
140 
141 /// \brief JSON/DBus matching Callable for std::variant (visitor)
142 ///
143 /// std::string specialization of MatchProbe enabling regex matching
144 template <>
145 struct MatchProbe<std::string>
146 {
147     /// \param probe the probe statement to match against
148     /// \param value the string value being matched to a probe
149     /// \return true if the dbusValue matched the probe otherwise false
matchMatchProbe150     static bool match(const nlohmann::json& probe, const std::string& value)
151     {
152         if (probe.is_string())
153         {
154             try
155             {
156                 std::regex search(probe);
157                 std::smatch regMatch;
158                 return std::regex_search(value, regMatch, search);
159             }
160             catch (const std::regex_error&)
161             {
162                 std::cerr << "Syntax error in regular expression: " << probe
163                           << " will never match";
164             }
165         }
166 
167         // Skip calling nlohmann here, since it will never match a non-string
168         // to a std::string
169         return false;
170     }
171 };
172 
173 /// \brief Forwarding JSON/DBus matching Callable for std::variant (visitor)
174 ///
175 /// Forward calls to the correct template instantiation of MatchProbe
176 struct MatchProbeForwarder
177 {
MatchProbeForwarderMatchProbeForwarder178     explicit MatchProbeForwarder(const nlohmann::json& probe) : probeRef(probe)
179     {}
180     const nlohmann::json& probeRef;
181 
182     template <typename T>
operator ()MatchProbeForwarder183     bool operator()(const T& dbusValue) const
184     {
185         return MatchProbe<T>::match(probeRef, dbusValue);
186     }
187 };
188 
matchProbe(const nlohmann::json & probe,const DBusValueVariant & dbusValue)189 bool matchProbe(const nlohmann::json& probe, const DBusValueVariant& dbusValue)
190 {
191     return std::visit(MatchProbeForwarder(probe), dbusValue);
192 }
193