blob: 4f431d5ef3644407636cb80d3be061287a458830 [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>
Willy Tu58881d02022-10-02 20:46:45 +00009#include <unordered_set>
Willy Tuaba14d32023-01-31 14:19:59 -080010#include <utility>
11#include <vector>
12
13void addObjectMapResult(std::vector<InterfaceMapType::value_type>& objectMap,
14 const std::string& objectPath,
15 const ConnectionNames::value_type& interfaceMap)
16{
17 // Adds an object path/service name/interface list entry to
18 // the results of GetSubTree and GetAncestors.
19 // If an entry for the object path already exists, just add the
20 // service name and interfaces to that entry, otherwise create
21 // a new entry.
Patrick Williams47b68cb2023-10-20 11:20:07 -050022 auto entry = std::find_if(
23 objectMap.begin(), objectMap.end(),
24 [&objectPath](const auto& i) { return objectPath == i.first; });
Willy Tuaba14d32023-01-31 14:19:59 -080025
26 if (entry != objectMap.end())
27 {
28 entry->second.emplace(interfaceMap);
29 }
30 else
31 {
32 InterfaceMapType::value_type object;
33 object.first = objectPath;
34 object.second.emplace(interfaceMap);
35 objectMap.push_back(object);
36 }
37}
38
39std::vector<InterfaceMapType::value_type>
40 getAncestors(const InterfaceMapType& interfaceMap, std::string reqPath,
41 std::vector<std::string>& interfaces)
42{
43 // Interfaces need to be sorted for intersect to function
44 std::sort(interfaces.begin(), interfaces.end());
45
46 if (reqPath.ends_with("/"))
47 {
48 reqPath.pop_back();
49 }
50 if (!reqPath.empty() && interfaceMap.find(reqPath) == interfaceMap.end())
51 {
52 throw sdbusplus::xyz::openbmc_project::Common::Error::
53 ResourceNotFound();
54 }
55
56 std::vector<InterfaceMapType::value_type> ret;
57 for (const auto& objectPath : interfaceMap)
58 {
59 const auto& thisPath = objectPath.first;
60
61 if (reqPath == thisPath)
62 {
63 continue;
64 }
65
66 if (reqPath.starts_with(thisPath))
67 {
68 if (interfaces.empty())
69 {
70 ret.emplace_back(objectPath);
71 }
72 else
73 {
74 for (const auto& interfaceMap : objectPath.second)
75 {
76 std::vector<std::string> output(std::min(
77 interfaces.size(), interfaceMap.second.size()));
78 // Return iterator points at the first output elemtn,
79 // meaning that there are no intersections.
Patrick Williams9052ebd2024-08-16 15:22:16 -040080 if (std::set_intersection(
81 interfaces.begin(), interfaces.end(),
82 interfaceMap.second.begin(),
83 interfaceMap.second.end(), output.begin()) !=
84 output.begin())
Willy Tuaba14d32023-01-31 14:19:59 -080085 {
86 addObjectMapResult(ret, thisPath, interfaceMap);
87 }
88 }
89 }
90 }
91 }
92
93 return ret;
94}
95
96ConnectionNames getObject(const InterfaceMapType& interfaceMap,
97 const std::string& path,
98 std::vector<std::string>& interfaces)
99{
100 ConnectionNames results;
101
102 // Interfaces need to be sorted for intersect to function
103 std::sort(interfaces.begin(), interfaces.end());
104 auto pathRef = interfaceMap.find(path);
105 if (pathRef == interfaceMap.end())
106 {
107 throw sdbusplus::xyz::openbmc_project::Common::Error::
108 ResourceNotFound();
109 }
110 if (interfaces.empty())
111 {
112 return pathRef->second;
113 }
114 for (const auto& interfaceMap : pathRef->second)
115 {
116 std::vector<std::string> output(
117 std::min(interfaces.size(), interfaceMap.second.size()));
118 // Return iterator points at the first output elemtn,
119 // meaning that there are no intersections.
120 if (std::set_intersection(interfaces.begin(), interfaces.end(),
121 interfaceMap.second.begin(),
Patrick Williams9052ebd2024-08-16 15:22:16 -0400122 interfaceMap.second.end(), output.begin()) !=
123 output.begin())
Willy Tuaba14d32023-01-31 14:19:59 -0800124 {
125 results.emplace(interfaceMap.first, interfaceMap.second);
126 }
127 }
128
129 if (results.empty())
130 {
131 throw sdbusplus::xyz::openbmc_project::Common::Error::
132 ResourceNotFound();
133 }
134
135 return results;
136}
137
138std::vector<InterfaceMapType::value_type>
139 getSubTree(const InterfaceMapType& interfaceMap, std::string reqPath,
140 int32_t depth, std::vector<std::string>& interfaces)
141{
142 if (depth <= 0)
143 {
144 depth = std::numeric_limits<int32_t>::max();
145 }
146 // Interfaces need to be sorted for intersect to function
147 std::sort(interfaces.begin(), interfaces.end());
148
149 // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
150 // will be guaranteed not to have a trailing "/"
151 if (!reqPath.ends_with("/"))
152 {
153 reqPath += "/";
154 }
155 std::string_view reqPathStripped =
156 std::string_view(reqPath).substr(0, reqPath.size() - 1);
157
158 if (!reqPathStripped.empty() &&
159 interfaceMap.find(reqPathStripped) == interfaceMap.end())
160 {
161 throw sdbusplus::xyz::openbmc_project::Common::Error::
162 ResourceNotFound();
163 }
164
165 std::vector<InterfaceMapType::value_type> ret;
166 for (const auto& objectPath : interfaceMap)
167 {
168 const auto& thisPath = objectPath.first;
169
170 // Skip exact match on stripped search term
171 if (thisPath == reqPathStripped)
172 {
173 continue;
174 }
175
176 if (thisPath.starts_with(reqPath))
177 {
178 // count the number of slashes past the stripped search term
179 int32_t thisDepth = std::count(
180 thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
181 if (thisDepth <= depth)
182 {
183 for (const auto& interfaceMap : objectPath.second)
184 {
185 std::vector<std::string> output(std::min(
186 interfaces.size(), interfaceMap.second.size()));
187 // Return iterator points at the first output elemtn,
188 // meaning that there are no intersections.
189 if (std::set_intersection(
190 interfaces.begin(), interfaces.end(),
191 interfaceMap.second.begin(),
192 interfaceMap.second.end(),
193 output.begin()) != output.begin() ||
194 interfaces.empty())
195 {
196 addObjectMapResult(ret, thisPath, interfaceMap);
197 }
198 }
199 }
200 }
201 }
202
203 return ret;
204}
205
Patrick Williams9052ebd2024-08-16 15:22:16 -0400206std::vector<std::string>
207 getSubTreePaths(const InterfaceMapType& interfaceMap, std::string reqPath,
208 int32_t depth, std::vector<std::string>& interfaces)
Willy Tuaba14d32023-01-31 14:19:59 -0800209{
210 if (depth <= 0)
211 {
212 depth = std::numeric_limits<int32_t>::max();
213 }
214 // Interfaces need to be sorted for intersect to function
215 std::sort(interfaces.begin(), interfaces.end());
216
217 // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
218 // will be guaranteed not to have a trailing "/"
219 if (!reqPath.ends_with("/"))
220 {
221 reqPath += "/";
222 }
223 std::string_view reqPathStripped =
224 std::string_view(reqPath).substr(0, reqPath.size() - 1);
225
226 if (!reqPathStripped.empty() &&
227 interfaceMap.find(reqPathStripped) == interfaceMap.end())
228 {
229 throw sdbusplus::xyz::openbmc_project::Common::Error::
230 ResourceNotFound();
231 }
232
233 std::vector<std::string> ret;
234 for (const auto& objectPath : interfaceMap)
235 {
236 const auto& thisPath = objectPath.first;
237
238 // Skip exact match on stripped search term
239 if (thisPath == reqPathStripped)
240 {
241 continue;
242 }
243
244 if (thisPath.starts_with(reqPath))
245 {
246 // count the number of slashes past the stripped search term
247 int thisDepth = std::count(
248 thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
249 if (thisDepth <= depth)
250 {
251 bool add = interfaces.empty();
252 for (const auto& interfaceMap : objectPath.second)
253 {
254 std::vector<std::string> output(std::min(
255 interfaces.size(), interfaceMap.second.size()));
256 // Return iterator points at the first output elemtn,
257 // meaning that there are no intersections.
Patrick Williams9052ebd2024-08-16 15:22:16 -0400258 if (std::set_intersection(
259 interfaces.begin(), interfaces.end(),
260 interfaceMap.second.begin(),
261 interfaceMap.second.end(), output.begin()) !=
262 output.begin())
Willy Tuaba14d32023-01-31 14:19:59 -0800263 {
264 add = true;
265 break;
266 }
267 }
268 if (add)
269 {
270 // TODO(ed) this is a copy
271 ret.emplace_back(thisPath);
272 }
273 }
274 }
275 }
276
277 return ret;
278}
Willy Tu58881d02022-10-02 20:46:45 +0000279
Patrick Williams9052ebd2024-08-16 15:22:16 -0400280std::vector<InterfaceMapType::value_type> getAssociatedSubTree(
281 const InterfaceMapType& interfaceMap,
282 const AssociationMaps& associationMaps,
283 const sdbusplus::message::object_path& associationPath,
284 const sdbusplus::message::object_path& reqPath, int32_t depth,
285 std::vector<std::string>& interfaces)
Willy Tu58881d02022-10-02 20:46:45 +0000286{
287 auto findEndpoint = associationMaps.ifaces.find(associationPath.str);
288 if (findEndpoint == associationMaps.ifaces.end())
289 {
290 return {};
291 }
292 const std::vector<std::string>& association =
293 std::get<endpointsPos>(findEndpoint->second);
294 std::unordered_set<std::string> associationSet(association.begin(),
295 association.end());
Patrick Williams8c250062024-08-23 12:28:07 -0400296 const std::vector<InterfaceMapType::value_type> interfacePairs =
Willy Tu58881d02022-10-02 20:46:45 +0000297 getSubTree(interfaceMap, reqPath, depth, interfaces);
298
299 std::vector<InterfaceMapType::value_type> output;
300 for (const InterfaceMapType::value_type& interfacePair : interfacePairs)
301 {
302 if (associationSet.contains(interfacePair.first))
303 {
304 output.emplace_back(interfacePair);
305 }
306 }
307 return output;
308}
309
310std::vector<std::string> getAssociatedSubTreePaths(
311 const InterfaceMapType& interfaceMap,
312 const AssociationMaps& associationMaps,
313 const sdbusplus::message::object_path& associationPath,
314 const sdbusplus::message::object_path& reqPath, int32_t depth,
315 std::vector<std::string>& interfaces)
316{
317 auto findEndpoint = associationMaps.ifaces.find(associationPath.str);
318 if (findEndpoint == associationMaps.ifaces.end())
319 {
320 return {};
321 }
322 const std::vector<std::string>& association =
323 std::get<endpointsPos>(findEndpoint->second);
324 std::unordered_set<std::string> associationSet(association.begin(),
325 association.end());
Patrick Williams8c250062024-08-23 12:28:07 -0400326 const std::vector<std::string> paths =
Willy Tu58881d02022-10-02 20:46:45 +0000327 getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
328
329 std::vector<std::string> output;
330 for (const auto& path : paths)
331 {
332 if (associationSet.contains(path))
333 {
334 output.emplace_back(path);
335 }
336 }
337 return output;
Patrick Williams1a19e6a2023-05-10 07:51:32 -0500338}
Lakshmi Yadlapatic3633232024-04-09 10:47:29 -0500339
340// This function works like getSubTreePaths() but only matching id with
341// the leaf-name instead of full path.
342std::vector<std::string> getSubTreePathsById(
343 const InterfaceMapType& interfaceMap, const std::string& id,
344 const std::string& objectPath, std::vector<std::string>& interfaces)
345{
346 std::sort(interfaces.begin(), interfaces.end());
347
348 std::string localObjectPath = objectPath;
349
350 if (!localObjectPath.ends_with("/"))
351 {
352 localObjectPath += "/";
353 }
354 std::string_view objectPathStripped =
355 std::string_view(localObjectPath).substr(0, localObjectPath.size() - 1);
356
357 if (!objectPathStripped.empty() &&
358 interfaceMap.find(objectPathStripped) == interfaceMap.end())
359 {
360 throw sdbusplus::xyz::openbmc_project::Common::Error::
361 ResourceNotFound();
362 }
363
364 std::vector<std::string> output;
365 for (const auto& path : interfaceMap)
366 {
367 const auto& thisPath = path.first;
368
369 // Skip exact match on stripped search term or
370 // the path does not end with the id
371 if (thisPath == objectPathStripped || !thisPath.ends_with("/" + id))
372 {
373 continue;
374 }
375
376 if (thisPath.starts_with(objectPath))
377 {
378 for (const auto& interfaceMap : path.second)
379 {
380 std::vector<std::string> tempoutput(
381 std::min(interfaces.size(), interfaceMap.second.size()));
382 if (std::set_intersection(
383 interfaces.begin(), interfaces.end(),
384 interfaceMap.second.begin(), interfaceMap.second.end(),
385 tempoutput.begin()) != tempoutput.begin())
386 {
387 output.emplace_back(thisPath);
388 break;
389 }
390 }
391 }
392 }
Lakshmi Yadlapatic3633232024-04-09 10:47:29 -0500393 return output;
394}
395
396std::vector<InterfaceMapType::value_type> getAssociatedSubTreeById(
397 const InterfaceMapType& interfaceMap,
398 const AssociationMaps& associationMaps, const std::string& id,
399 const std::string& objectPath, std::vector<std::string>& subtreeInterfaces,
400 const std::string& association,
401 std::vector<std::string>& endpointInterfaces)
402{
403 std::vector<std::string> subtreePaths =
404 getSubTreePathsById(interfaceMap, id, objectPath, subtreeInterfaces);
405
406 std::vector<InterfaceMapType::value_type> output;
407 for (const auto& subtreePath : subtreePaths)
408 {
409 // Form the association path
410 std::string associationPathStr = subtreePath + "/" + association;
411 sdbusplus::message::object_path associationPath(associationPathStr);
412
413 auto associatedSubTree =
414 getAssociatedSubTree(interfaceMap, associationMaps, associationPath,
415 objectPath, 0, endpointInterfaces);
416
417 output.insert(output.end(), associatedSubTree.begin(),
418 associatedSubTree.end());
419 }
420 return output;
421}
422
423std::vector<std::string> getAssociatedSubTreePathsById(
424 const InterfaceMapType& interfaceMap,
425 const AssociationMaps& associationMaps, const std::string& id,
426 const std::string& objectPath, std::vector<std::string>& subtreeInterfaces,
427 const std::string& association,
428 std::vector<std::string>& endpointInterfaces)
429{
430 std::vector<std::string> subtreePaths =
431 getSubTreePathsById(interfaceMap, id, objectPath, subtreeInterfaces);
432 std::vector<std::string> output;
433 for (const auto& subtreePath : subtreePaths)
434 {
435 // Form the association path
436 std::string associationPathStr = subtreePath + "/" + association;
437 sdbusplus::message::object_path associationPath(associationPathStr);
438
439 auto associatedSubTree = getAssociatedSubTreePaths(
440 interfaceMap, associationMaps, associationPath, objectPath, 0,
441 endpointInterfaces);
442
443 output.insert(output.end(), associatedSubTree.begin(),
444 associatedSubTree.end());
445 }
446
447 return output;
448}