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