| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 1 | #include "dbus_interface.hpp" | 
 | 2 |  | 
 | 3 | #include "perform_probe.hpp" | 
| Christopher Meis | 59ef1e7 | 2025-04-16 08:53:25 +0200 | [diff] [blame] | 4 | #include "utils.hpp" | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 5 |  | 
 | 6 | #include <boost/algorithm/string/case_conv.hpp> | 
 | 7 | #include <boost/container/flat_map.hpp> | 
 | 8 |  | 
| Christopher Meis | 59ef1e7 | 2025-04-16 08:53:25 +0200 | [diff] [blame] | 9 | #include <fstream> | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 10 | #include <regex> | 
 | 11 | #include <string> | 
 | 12 | #include <vector> | 
 | 13 |  | 
 | 14 | using JsonVariantType = | 
 | 15 |     std::variant<std::vector<std::string>, std::vector<double>, std::string, | 
 | 16 |                  int64_t, uint64_t, double, int32_t, uint32_t, int16_t, | 
 | 17 |                  uint16_t, uint8_t, bool>; | 
 | 18 |  | 
 | 19 | namespace dbus_interface | 
 | 20 | { | 
 | 21 |  | 
 | 22 | const std::regex illegalDbusPathRegex("[^A-Za-z0-9_.]"); | 
 | 23 | const std::regex illegalDbusMemberRegex("[^A-Za-z0-9_]"); | 
 | 24 |  | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 25 | EMDBusInterface::EMDBusInterface(boost::asio::io_context& io, | 
 | 26 |                                  sdbusplus::asio::object_server& objServer) : | 
 | 27 |     io(io), objServer(objServer) | 
 | 28 | {} | 
 | 29 |  | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 30 | void tryIfaceInitialize(std::shared_ptr<sdbusplus::asio::dbus_interface>& iface) | 
 | 31 | { | 
 | 32 |     try | 
 | 33 |     { | 
 | 34 |         iface->initialize(); | 
 | 35 |     } | 
 | 36 |     catch (std::exception& e) | 
 | 37 |     { | 
 | 38 |         std::cerr << "Unable to initialize dbus interface : " << e.what() | 
 | 39 |                   << "\n" | 
 | 40 |                   << "object Path : " << iface->get_object_path() << "\n" | 
 | 41 |                   << "interface name : " << iface->get_interface_name() << "\n"; | 
 | 42 |     } | 
 | 43 | } | 
 | 44 |  | 
| Alexander Hansen | 57604ed | 2025-06-27 13:22:28 +0200 | [diff] [blame] | 45 | std::shared_ptr<sdbusplus::asio::dbus_interface> | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 46 |     EMDBusInterface::createInterface(const std::string& path, | 
 | 47 |                                      const std::string& interface, | 
 | 48 |                                      const std::string& parent, bool checkNull) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 49 | { | 
 | 50 |     // on first add we have no reason to check for null before add, as there | 
 | 51 |     // won't be any. For dynamically added interfaces, we check for null so that | 
 | 52 |     // a constant delete/add will not create a memory leak | 
 | 53 |  | 
 | 54 |     auto ptr = objServer.add_interface(path, interface); | 
 | 55 |     auto& dataVector = inventory[parent]; | 
 | 56 |     if (checkNull) | 
 | 57 |     { | 
 | 58 |         auto it = std::find_if(dataVector.begin(), dataVector.end(), | 
 | 59 |                                [](const auto& p) { return p.expired(); }); | 
 | 60 |         if (it != dataVector.end()) | 
 | 61 |         { | 
 | 62 |             *it = ptr; | 
 | 63 |             return ptr; | 
 | 64 |         } | 
 | 65 |     } | 
 | 66 |     dataVector.emplace_back(ptr); | 
 | 67 |     return ptr; | 
 | 68 | } | 
 | 69 |  | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 70 | void EMDBusInterface::createDeleteObjectMethod( | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 71 |     const std::string& jsonPointerPath, | 
 | 72 |     const std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 73 |     nlohmann::json& systemConfiguration) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 74 | { | 
 | 75 |     std::weak_ptr<sdbusplus::asio::dbus_interface> interface = iface; | 
 | 76 |     iface->register_method( | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 77 |         "Delete", [this, &systemConfiguration, interface, | 
 | 78 |                    jsonPointerPath{std::string(jsonPointerPath)}]() { | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 79 |             std::shared_ptr<sdbusplus::asio::dbus_interface> dbusInterface = | 
 | 80 |                 interface.lock(); | 
 | 81 |             if (!dbusInterface) | 
 | 82 |             { | 
 | 83 |                 // this technically can't happen as the pointer is pointing to | 
 | 84 |                 // us | 
 | 85 |                 throw DBusInternalError(); | 
 | 86 |             } | 
 | 87 |             nlohmann::json::json_pointer ptr(jsonPointerPath); | 
 | 88 |             systemConfiguration[ptr] = nullptr; | 
 | 89 |  | 
 | 90 |             // todo(james): dig through sdbusplus to find out why we can't | 
 | 91 |             // delete it in a method call | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 92 |             boost::asio::post(io, [dbusInterface, this]() mutable { | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 93 |                 objServer.remove_interface(dbusInterface); | 
 | 94 |             }); | 
 | 95 |  | 
| Christopher Meis | f725257 | 2025-06-11 13:22:05 +0200 | [diff] [blame] | 96 |             if (!writeJsonFiles(systemConfiguration)) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 97 |             { | 
 | 98 |                 std::cerr << "error setting json file\n"; | 
 | 99 |                 throw DBusInternalError(); | 
 | 100 |             } | 
 | 101 |         }); | 
 | 102 | } | 
 | 103 |  | 
| Alexander Hansen | d72dc33 | 2025-06-10 10:49:24 +0200 | [diff] [blame] | 104 | static bool checkArrayElementsSameType(nlohmann::json& value) | 
 | 105 | { | 
 | 106 |     nlohmann::json::array_t* arr = value.get_ptr<nlohmann::json::array_t*>(); | 
 | 107 |     if (arr == nullptr) | 
 | 108 |     { | 
 | 109 |         return false; | 
 | 110 |     } | 
 | 111 |  | 
 | 112 |     if (arr->empty()) | 
 | 113 |     { | 
 | 114 |         return true; | 
 | 115 |     } | 
 | 116 |  | 
 | 117 |     nlohmann::json::value_t firstType = value[0].type(); | 
 | 118 |     return std::ranges::all_of(value, [firstType](const nlohmann::json& el) { | 
 | 119 |         return el.type() == firstType; | 
 | 120 |     }); | 
 | 121 | } | 
 | 122 |  | 
| Alexander Hansen | 91e360e | 2025-06-10 12:21:30 +0200 | [diff] [blame] | 123 | static nlohmann::json::value_t getDBusType( | 
 | 124 |     const nlohmann::json& value, nlohmann::json::value_t type, | 
| Alexander Hansen | 17f8e6a | 2025-06-10 12:10:09 +0200 | [diff] [blame] | 125 |     sdbusplus::asio::PropertyPermission permission) | 
 | 126 | { | 
 | 127 |     const bool array = value.type() == nlohmann::json::value_t::array; | 
 | 128 |  | 
 | 129 |     if (permission == sdbusplus::asio::PropertyPermission::readWrite) | 
 | 130 |     { | 
 | 131 |         // all setable numbers are doubles as it is difficult to always | 
 | 132 |         // create a configuration file with all whole numbers as decimals | 
 | 133 |         // i.e. 1.0 | 
 | 134 |         if (array) | 
 | 135 |         { | 
 | 136 |             if (value[0].is_number()) | 
 | 137 |             { | 
| Alexander Hansen | 91e360e | 2025-06-10 12:21:30 +0200 | [diff] [blame] | 138 |                 return nlohmann::json::value_t::number_float; | 
| Alexander Hansen | 17f8e6a | 2025-06-10 12:10:09 +0200 | [diff] [blame] | 139 |             } | 
 | 140 |         } | 
 | 141 |         else if (value.is_number()) | 
 | 142 |         { | 
| Alexander Hansen | 91e360e | 2025-06-10 12:21:30 +0200 | [diff] [blame] | 143 |             return nlohmann::json::value_t::number_float; | 
| Alexander Hansen | 17f8e6a | 2025-06-10 12:10:09 +0200 | [diff] [blame] | 144 |         } | 
 | 145 |     } | 
 | 146 |  | 
| Alexander Hansen | 91e360e | 2025-06-10 12:21:30 +0200 | [diff] [blame] | 147 |     return type; | 
 | 148 | } | 
 | 149 |  | 
 | 150 | static void populateInterfacePropertyFromJson( | 
 | 151 |     nlohmann::json& systemConfiguration, const std::string& path, | 
 | 152 |     const nlohmann::json& key, const nlohmann::json& value, | 
 | 153 |     nlohmann::json::value_t type, | 
 | 154 |     std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
 | 155 |     sdbusplus::asio::PropertyPermission permission) | 
 | 156 | { | 
 | 157 |     const auto modifiedType = getDBusType(value, type, permission); | 
 | 158 |  | 
 | 159 |     switch (modifiedType) | 
| Alexander Hansen | 17f8e6a | 2025-06-10 12:10:09 +0200 | [diff] [blame] | 160 |     { | 
 | 161 |         case (nlohmann::json::value_t::boolean): | 
 | 162 |         { | 
| Alexander Hansen | 0123f8a | 2025-06-27 12:11:08 +0200 | [diff] [blame] | 163 |             // todo: array of bool isn't detected correctly by | 
 | 164 |             // sdbusplus, change it to numbers | 
 | 165 |             addValueToDBus<uint64_t, bool>(key, value, *iface, permission, | 
 | 166 |                                            systemConfiguration, path); | 
| Alexander Hansen | 17f8e6a | 2025-06-10 12:10:09 +0200 | [diff] [blame] | 167 |             break; | 
 | 168 |         } | 
 | 169 |         case (nlohmann::json::value_t::number_integer): | 
 | 170 |         { | 
 | 171 |             addValueToDBus<int64_t>(key, value, *iface, permission, | 
 | 172 |                                     systemConfiguration, path); | 
 | 173 |             break; | 
 | 174 |         } | 
 | 175 |         case (nlohmann::json::value_t::number_unsigned): | 
 | 176 |         { | 
 | 177 |             addValueToDBus<uint64_t>(key, value, *iface, permission, | 
 | 178 |                                      systemConfiguration, path); | 
 | 179 |             break; | 
 | 180 |         } | 
 | 181 |         case (nlohmann::json::value_t::number_float): | 
 | 182 |         { | 
 | 183 |             addValueToDBus<double>(key, value, *iface, permission, | 
 | 184 |                                    systemConfiguration, path); | 
 | 185 |             break; | 
 | 186 |         } | 
 | 187 |         case (nlohmann::json::value_t::string): | 
 | 188 |         { | 
 | 189 |             addValueToDBus<std::string>(key, value, *iface, permission, | 
 | 190 |                                         systemConfiguration, path); | 
 | 191 |             break; | 
 | 192 |         } | 
 | 193 |         default: | 
 | 194 |         { | 
 | 195 |             std::cerr << "Unexpected json type in system configuration " << key | 
 | 196 |                       << ": " << value.type_name() << "\n"; | 
 | 197 |             break; | 
 | 198 |         } | 
 | 199 |     } | 
 | 200 | } | 
 | 201 |  | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 202 | // adds simple json types to interface's properties | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 203 | void EMDBusInterface::populateInterfaceFromJson( | 
 | 204 |     nlohmann::json& systemConfiguration, const std::string& jsonPointerPath, | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 205 |     std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 206 |     nlohmann::json& dict, sdbusplus::asio::PropertyPermission permission) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 207 | { | 
 | 208 |     for (const auto& [key, value] : dict.items()) | 
 | 209 |     { | 
 | 210 |         auto type = value.type(); | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 211 |         if (value.type() == nlohmann::json::value_t::array) | 
 | 212 |         { | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 213 |             if (value.empty()) | 
 | 214 |             { | 
 | 215 |                 continue; | 
 | 216 |             } | 
 | 217 |             type = value[0].type(); | 
| Alexander Hansen | d72dc33 | 2025-06-10 10:49:24 +0200 | [diff] [blame] | 218 |             if (!checkArrayElementsSameType(value)) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 219 |             { | 
 | 220 |                 std::cerr << "dbus format error" << value << "\n"; | 
 | 221 |                 continue; | 
 | 222 |             } | 
 | 223 |         } | 
 | 224 |         if (type == nlohmann::json::value_t::object) | 
 | 225 |         { | 
 | 226 |             continue; // handled elsewhere | 
 | 227 |         } | 
 | 228 |  | 
 | 229 |         std::string path = jsonPointerPath; | 
 | 230 |         path.append("/").append(key); | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 231 |  | 
| Alexander Hansen | 17f8e6a | 2025-06-10 12:10:09 +0200 | [diff] [blame] | 232 |         populateInterfacePropertyFromJson(systemConfiguration, path, key, value, | 
 | 233 |                                           type, iface, permission); | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 234 |     } | 
 | 235 |     if (permission == sdbusplus::asio::PropertyPermission::readWrite) | 
 | 236 |     { | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 237 |         createDeleteObjectMethod(jsonPointerPath, iface, systemConfiguration); | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 238 |     } | 
 | 239 |     tryIfaceInitialize(iface); | 
 | 240 | } | 
 | 241 |  | 
| Alexander Hansen | 57604ed | 2025-06-27 13:22:28 +0200 | [diff] [blame] | 242 | void EMDBusInterface::createAddObjectMethod( | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 243 |     const std::string& jsonPointerPath, const std::string& path, | 
 | 244 |     nlohmann::json& systemConfiguration, const std::string& board) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 245 | { | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 246 |     std::shared_ptr<sdbusplus::asio::dbus_interface> iface = | 
 | 247 |         createInterface(path, "xyz.openbmc_project.AddObject", board); | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 248 |  | 
 | 249 |     iface->register_method( | 
 | 250 |         "AddObject", | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 251 |         [&systemConfiguration, jsonPointerPath{std::string(jsonPointerPath)}, | 
 | 252 |          path{std::string(path)}, board, | 
| Alexander Hansen | 57604ed | 2025-06-27 13:22:28 +0200 | [diff] [blame] | 253 |          this](const boost::container::flat_map<std::string, JsonVariantType>& | 
 | 254 |                    data) { | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 255 |             nlohmann::json::json_pointer ptr(jsonPointerPath); | 
 | 256 |             nlohmann::json& base = systemConfiguration[ptr]; | 
 | 257 |             auto findExposes = base.find("Exposes"); | 
 | 258 |  | 
 | 259 |             if (findExposes == base.end()) | 
 | 260 |             { | 
 | 261 |                 throw std::invalid_argument("Entity must have children."); | 
 | 262 |             } | 
 | 263 |  | 
 | 264 |             // this will throw invalid-argument to sdbusplus if invalid json | 
 | 265 |             nlohmann::json newData{}; | 
 | 266 |             for (const auto& item : data) | 
 | 267 |             { | 
 | 268 |                 nlohmann::json& newJson = newData[item.first]; | 
 | 269 |                 std::visit( | 
 | 270 |                     [&newJson](auto&& val) { | 
 | 271 |                         newJson = std::forward<decltype(val)>(val); | 
 | 272 |                     }, | 
 | 273 |                     item.second); | 
 | 274 |             } | 
 | 275 |  | 
 | 276 |             auto findName = newData.find("Name"); | 
 | 277 |             auto findType = newData.find("Type"); | 
 | 278 |             if (findName == newData.end() || findType == newData.end()) | 
 | 279 |             { | 
 | 280 |                 throw std::invalid_argument("AddObject missing Name or Type"); | 
 | 281 |             } | 
 | 282 |             const std::string* type = findType->get_ptr<const std::string*>(); | 
 | 283 |             const std::string* name = findName->get_ptr<const std::string*>(); | 
 | 284 |             if (type == nullptr || name == nullptr) | 
 | 285 |             { | 
 | 286 |                 throw std::invalid_argument("Type and Name must be a string."); | 
 | 287 |             } | 
 | 288 |  | 
 | 289 |             bool foundNull = false; | 
 | 290 |             size_t lastIndex = 0; | 
 | 291 |             // we add in the "exposes" | 
 | 292 |             for (const auto& expose : *findExposes) | 
 | 293 |             { | 
 | 294 |                 if (expose.is_null()) | 
 | 295 |                 { | 
 | 296 |                     foundNull = true; | 
 | 297 |                     continue; | 
 | 298 |                 } | 
 | 299 |  | 
 | 300 |                 if (expose["Name"] == *name && expose["Type"] == *type) | 
 | 301 |                 { | 
 | 302 |                     throw std::invalid_argument( | 
 | 303 |                         "Field already in JSON, not adding"); | 
 | 304 |                 } | 
 | 305 |  | 
 | 306 |                 if (foundNull) | 
 | 307 |                 { | 
 | 308 |                     continue; | 
 | 309 |                 } | 
 | 310 |  | 
 | 311 |                 lastIndex++; | 
 | 312 |             } | 
 | 313 |  | 
| Marc Olberding | d10dd46 | 2025-08-22 11:58:46 -0700 | [diff] [blame] | 314 |             if constexpr (ENABLE_RUNTIME_VALIDATE_JSON) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 315 |             { | 
| Marc Olberding | d10dd46 | 2025-08-22 11:58:46 -0700 | [diff] [blame] | 316 |                 const std::filesystem::path schemaPath = | 
 | 317 |                     std::filesystem::path(schemaDirectory) / | 
 | 318 |                     "exposes_record.json"; | 
 | 319 |  | 
 | 320 |                 std::ifstream schemaFile{schemaPath}; | 
 | 321 |  | 
 | 322 |                 if (!schemaFile.good()) | 
 | 323 |                 { | 
 | 324 |                     throw std::invalid_argument( | 
 | 325 |                         "No schema avaliable, cannot validate."); | 
 | 326 |                 } | 
 | 327 |                 nlohmann::json schema = | 
 | 328 |                     nlohmann::json::parse(schemaFile, nullptr, false, true); | 
 | 329 |                 if (schema.is_discarded()) | 
 | 330 |                 { | 
 | 331 |                     std::cerr << "Schema not legal" << *type << ".json\n"; | 
 | 332 |                     throw DBusInternalError(); | 
 | 333 |                 } | 
 | 334 |  | 
 | 335 |                 if (!validateJson(schema, newData)) | 
 | 336 |                 { | 
 | 337 |                     throw std::invalid_argument("Data does not match schema"); | 
 | 338 |                 } | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 339 |             } | 
| Marc Olberding | d10dd46 | 2025-08-22 11:58:46 -0700 | [diff] [blame] | 340 |  | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 341 |             if (foundNull) | 
 | 342 |             { | 
 | 343 |                 findExposes->at(lastIndex) = newData; | 
 | 344 |             } | 
 | 345 |             else | 
 | 346 |             { | 
 | 347 |                 findExposes->push_back(newData); | 
 | 348 |             } | 
| Christopher Meis | f725257 | 2025-06-11 13:22:05 +0200 | [diff] [blame] | 349 |             if (!writeJsonFiles(systemConfiguration)) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 350 |             { | 
 | 351 |                 std::cerr << "Error writing json files\n"; | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 352 |             } | 
 | 353 |             std::string dbusName = *name; | 
 | 354 |  | 
 | 355 |             std::regex_replace(dbusName.begin(), dbusName.begin(), | 
 | 356 |                                dbusName.end(), illegalDbusMemberRegex, "_"); | 
 | 357 |  | 
 | 358 |             std::shared_ptr<sdbusplus::asio::dbus_interface> interface = | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 359 |                 createInterface(path + "/" + dbusName, | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 360 |                                 "xyz.openbmc_project.Configuration." + *type, | 
 | 361 |                                 board, true); | 
 | 362 |             // permission is read-write, as since we just created it, must be | 
 | 363 |             // runtime modifiable | 
 | 364 |             populateInterfaceFromJson( | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 365 |                 systemConfiguration, | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 366 |                 jsonPointerPath + "/Exposes/" + std::to_string(lastIndex), | 
| Alexander Hansen | 8973725 | 2025-08-04 15:15:13 +0200 | [diff] [blame] | 367 |                 interface, newData, | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 368 |                 sdbusplus::asio::PropertyPermission::readWrite); | 
 | 369 |         }); | 
 | 370 |     tryIfaceInitialize(iface); | 
 | 371 | } | 
 | 372 |  | 
 | 373 | std::vector<std::weak_ptr<sdbusplus::asio::dbus_interface>>& | 
| Alexander Hansen | 57604ed | 2025-06-27 13:22:28 +0200 | [diff] [blame] | 374 |     EMDBusInterface::getDeviceInterfaces(const nlohmann::json& device) | 
| Christopher Meis | 12bea9b | 2025-04-03 10:14:42 +0200 | [diff] [blame] | 375 | { | 
 | 376 |     return inventory[device["Name"].get<std::string>()]; | 
 | 377 | } | 
 | 378 |  | 
 | 379 | } // namespace dbus_interface |