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