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