1 #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 12 void 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 38 std::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 95 ConnectionNames 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 137 std::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 205 std::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 } 278