blob: 1a362ab783c4acf3c1e5073ce3a991467416e830 [file] [log] [blame]
Willy Tuaba14d32023-01-31 14:19:59 -08001#include "handler.hpp"
2
3#include "types.hpp"
4
5#include <xyz/openbmc_project/Common/error.hpp>
6
7#include <algorithm>
8#include <string>
9#include <utility>
10#include <vector>
11
12void addObjectMapResult(std::vector<InterfaceMapType::value_type>& objectMap,
13 const std::string& objectPath,
14 const ConnectionNames::value_type& interfaceMap)
15{
16 // Adds an object path/service name/interface list entry to
17 // the results of GetSubTree and GetAncestors.
18 // If an entry for the object path already exists, just add the
19 // service name and interfaces to that entry, otherwise create
20 // a new entry.
21 auto entry = std::find_if(
22 objectMap.begin(), objectMap.end(),
23 [&objectPath](const auto& i) { return objectPath == i.first; });
24
25 if (entry != objectMap.end())
26 {
27 entry->second.emplace(interfaceMap);
28 }
29 else
30 {
31 InterfaceMapType::value_type object;
32 object.first = objectPath;
33 object.second.emplace(interfaceMap);
34 objectMap.push_back(object);
35 }
36}
37
38std::vector<InterfaceMapType::value_type>
39 getAncestors(const InterfaceMapType& interfaceMap, std::string reqPath,
40 std::vector<std::string>& interfaces)
41{
42 // Interfaces need to be sorted for intersect to function
43 std::sort(interfaces.begin(), interfaces.end());
44
45 if (reqPath.ends_with("/"))
46 {
47 reqPath.pop_back();
48 }
49 if (!reqPath.empty() && interfaceMap.find(reqPath) == interfaceMap.end())
50 {
51 throw sdbusplus::xyz::openbmc_project::Common::Error::
52 ResourceNotFound();
53 }
54
55 std::vector<InterfaceMapType::value_type> ret;
56 for (const auto& objectPath : interfaceMap)
57 {
58 const auto& thisPath = objectPath.first;
59
60 if (reqPath == thisPath)
61 {
62 continue;
63 }
64
65 if (reqPath.starts_with(thisPath))
66 {
67 if (interfaces.empty())
68 {
69 ret.emplace_back(objectPath);
70 }
71 else
72 {
73 for (const auto& interfaceMap : objectPath.second)
74 {
75 std::vector<std::string> output(std::min(
76 interfaces.size(), interfaceMap.second.size()));
77 // Return iterator points at the first output elemtn,
78 // meaning that there are no intersections.
79 if (std::set_intersection(interfaces.begin(),
80 interfaces.end(),
81 interfaceMap.second.begin(),
82 interfaceMap.second.end(),
83 output.begin()) != output.begin())
84 {
85 addObjectMapResult(ret, thisPath, interfaceMap);
86 }
87 }
88 }
89 }
90 }
91
92 return ret;
93}
94
95ConnectionNames getObject(const InterfaceMapType& interfaceMap,
96 const std::string& path,
97 std::vector<std::string>& interfaces)
98{
99 ConnectionNames results;
100
101 // Interfaces need to be sorted for intersect to function
102 std::sort(interfaces.begin(), interfaces.end());
103 auto pathRef = interfaceMap.find(path);
104 if (pathRef == interfaceMap.end())
105 {
106 throw sdbusplus::xyz::openbmc_project::Common::Error::
107 ResourceNotFound();
108 }
109 if (interfaces.empty())
110 {
111 return pathRef->second;
112 }
113 for (const auto& interfaceMap : pathRef->second)
114 {
115 std::vector<std::string> output(
116 std::min(interfaces.size(), interfaceMap.second.size()));
117 // Return iterator points at the first output elemtn,
118 // meaning that there are no intersections.
119 if (std::set_intersection(interfaces.begin(), interfaces.end(),
120 interfaceMap.second.begin(),
121 interfaceMap.second.end(),
122 output.begin()) != output.begin())
123 {
124 results.emplace(interfaceMap.first, interfaceMap.second);
125 }
126 }
127
128 if (results.empty())
129 {
130 throw sdbusplus::xyz::openbmc_project::Common::Error::
131 ResourceNotFound();
132 }
133
134 return results;
135}
136
137std::vector<InterfaceMapType::value_type>
138 getSubTree(const InterfaceMapType& interfaceMap, std::string reqPath,
139 int32_t depth, std::vector<std::string>& interfaces)
140{
141 if (depth <= 0)
142 {
143 depth = std::numeric_limits<int32_t>::max();
144 }
145 // Interfaces need to be sorted for intersect to function
146 std::sort(interfaces.begin(), interfaces.end());
147
148 // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
149 // will be guaranteed not to have a trailing "/"
150 if (!reqPath.ends_with("/"))
151 {
152 reqPath += "/";
153 }
154 std::string_view reqPathStripped =
155 std::string_view(reqPath).substr(0, reqPath.size() - 1);
156
157 if (!reqPathStripped.empty() &&
158 interfaceMap.find(reqPathStripped) == interfaceMap.end())
159 {
160 throw sdbusplus::xyz::openbmc_project::Common::Error::
161 ResourceNotFound();
162 }
163
164 std::vector<InterfaceMapType::value_type> ret;
165 for (const auto& objectPath : interfaceMap)
166 {
167 const auto& thisPath = objectPath.first;
168
169 // Skip exact match on stripped search term
170 if (thisPath == reqPathStripped)
171 {
172 continue;
173 }
174
175 if (thisPath.starts_with(reqPath))
176 {
177 // count the number of slashes past the stripped search term
178 int32_t thisDepth = std::count(
179 thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
180 if (thisDepth <= depth)
181 {
182 for (const auto& interfaceMap : objectPath.second)
183 {
184 std::vector<std::string> output(std::min(
185 interfaces.size(), interfaceMap.second.size()));
186 // Return iterator points at the first output elemtn,
187 // meaning that there are no intersections.
188 if (std::set_intersection(
189 interfaces.begin(), interfaces.end(),
190 interfaceMap.second.begin(),
191 interfaceMap.second.end(),
192 output.begin()) != output.begin() ||
193 interfaces.empty())
194 {
195 addObjectMapResult(ret, thisPath, interfaceMap);
196 }
197 }
198 }
199 }
200 }
201
202 return ret;
203}
204
205std::vector<std::string> getSubTreePaths(const InterfaceMapType& interfaceMap,
206 std::string reqPath, int32_t depth,
207 std::vector<std::string>& interfaces)
208{
209 if (depth <= 0)
210 {
211 depth = std::numeric_limits<int32_t>::max();
212 }
213 // Interfaces need to be sorted for intersect to function
214 std::sort(interfaces.begin(), interfaces.end());
215
216 // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
217 // will be guaranteed not to have a trailing "/"
218 if (!reqPath.ends_with("/"))
219 {
220 reqPath += "/";
221 }
222 std::string_view reqPathStripped =
223 std::string_view(reqPath).substr(0, reqPath.size() - 1);
224
225 if (!reqPathStripped.empty() &&
226 interfaceMap.find(reqPathStripped) == interfaceMap.end())
227 {
228 throw sdbusplus::xyz::openbmc_project::Common::Error::
229 ResourceNotFound();
230 }
231
232 std::vector<std::string> ret;
233 for (const auto& objectPath : interfaceMap)
234 {
235 const auto& thisPath = objectPath.first;
236
237 // Skip exact match on stripped search term
238 if (thisPath == reqPathStripped)
239 {
240 continue;
241 }
242
243 if (thisPath.starts_with(reqPath))
244 {
245 // count the number of slashes past the stripped search term
246 int thisDepth = std::count(
247 thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
248 if (thisDepth <= depth)
249 {
250 bool add = interfaces.empty();
251 for (const auto& interfaceMap : objectPath.second)
252 {
253 std::vector<std::string> output(std::min(
254 interfaces.size(), interfaceMap.second.size()));
255 // Return iterator points at the first output elemtn,
256 // meaning that there are no intersections.
257 if (std::set_intersection(interfaces.begin(),
258 interfaces.end(),
259 interfaceMap.second.begin(),
260 interfaceMap.second.end(),
261 output.begin()) != output.begin())
262 {
263 add = true;
264 break;
265 }
266 }
267 if (add)
268 {
269 // TODO(ed) this is a copy
270 ret.emplace_back(thisPath);
271 }
272 }
273 }
274 }
275
276 return ret;
277}