1 // SPDX-License-Identifier: Apache-2.0 2 3 /**@file functions.cpp*/ 4 5 #include "config.h" 6 7 #include "functions.hpp" 8 9 #include <nlohmann/json.hpp> 10 #include <phosphor-logging/log.hpp> 11 #include <sdbusplus/bus.hpp> 12 #include <sdbusplus/bus/match.hpp> 13 #include <sdbusplus/exception.hpp> 14 #include <sdbusplus/message.hpp> 15 #include <sdeventplus/event.hpp> 16 17 #include <filesystem> 18 #include <fstream> 19 #include <functional> 20 #include <iostream> 21 #include <map> 22 #include <memory> 23 #include <string> 24 #include <variant> 25 #include <vector> 26 27 namespace functions 28 { 29 namespace process_hostfirmware 30 { 31 32 using namespace phosphor::logging; 33 34 /** 35 * @brief Issue callbacks safely 36 * 37 * std::function can be empty, so this wrapper method checks for that prior to 38 * calling it to avoid std::bad_function_call 39 * 40 * @tparam Sig the types of the std::function arguments 41 * @tparam Args the deduced argument types 42 * @param[in] callback the callback being wrapped 43 * @param[in] args the callback arguments 44 */ 45 template <typename... Sig, typename... Args> 46 void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args) 47 { 48 if (callback) 49 { 50 callback(std::forward<Args>(args)...); 51 } 52 } 53 54 /** 55 * @brief Get file extensions for IBMCompatibleSystem 56 * 57 * IBM host firmware can be deployed as blobs (files) in a filesystem. Host 58 * firmware blobs for different values of 59 * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with 60 * different filename extensions. getExtensionsForIbmCompatibleSystem 61 * maintains the mapping from a given value of 62 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of 63 * filename extensions. 64 * 65 * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and 66 * the extensions parameter is reset with the map entry. If no mapping is 67 * found getExtensionsForIbmCompatibleSystem returns false and extensions is 68 * unmodified. 69 * 70 * @param[in] extensionMap a map of 71 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 72 * file extensions. 73 * @param[in] ibmCompatibleSystem The names property of an instance of 74 * xyz.openbmc_project.Configuration.IBMCompatibleSystem 75 * @param[out] extentions the host firmware blob file extensions 76 * @return true if an entry was found, otherwise false 77 */ 78 bool getExtensionsForIbmCompatibleSystem( 79 const std::map<std::string, std::vector<std::string>>& extensionMap, 80 const std::vector<std::string>& ibmCompatibleSystem, 81 std::vector<std::string>& extensions) 82 { 83 for (const auto& system : ibmCompatibleSystem) 84 { 85 auto extensionMapIterator = extensionMap.find(system); 86 if (extensionMapIterator != extensionMap.end()) 87 { 88 extensions = extensionMapIterator->second; 89 return true; 90 } 91 } 92 93 return false; 94 } 95 96 /** 97 * @brief Write host firmware well-known name 98 * 99 * A wrapper around std::filesystem::create_symlink that avoids EEXIST by 100 * deleting any pre-existing file. 101 * 102 * @param[in] linkTarget The link target argument to 103 * std::filesystem::create_symlink 104 * @param[in] linkPath The link path argument to std::filesystem::create_symlink 105 * @param[in] errorCallback A callback made in the event of filesystem errors. 106 */ 107 void writeLink(const std::filesystem::path& linkTarget, 108 const std::filesystem::path& linkPath, 109 const ErrorCallbackType& errorCallback) 110 { 111 std::error_code ec; 112 113 // remove files with the same name as the symlink to be created, 114 // otherwise symlink will fail with EEXIST. 115 if (!std::filesystem::remove(linkPath, ec)) 116 { 117 if (ec) 118 { 119 makeCallback(errorCallback, linkPath, ec); 120 return; 121 } 122 } 123 124 std::filesystem::create_symlink(linkTarget, linkPath, ec); 125 if (ec) 126 { 127 makeCallback(errorCallback, linkPath, ec); 128 return; 129 } 130 } 131 132 /** 133 * @brief Find host firmware blob files that need well-known names 134 * 135 * The IBM host firmware runtime looks for data and/or additional code while 136 * bootstraping in files with well-known names. findLinks uses the provided 137 * extensions argument to find host firmware blob files that require a 138 * well-known name. When a blob is found, issue the provided callback 139 * (typically a function that will write a symlink). 140 * 141 * @param[in] hostFirmwareDirectory The directory in which findLinks should 142 * look for host firmware blob files that need well-known names. 143 * @param[in] extentions The extensions of the firmware blob files denote a 144 * host firmware blob file requires a well-known name. 145 * @param[in] errorCallback A callback made in the event of filesystem errors. 146 * @param[in] linkCallback A callback made when host firmware blob files 147 * needing a well known name are found. 148 */ 149 void findLinks(const std::filesystem::path& hostFirmwareDirectory, 150 const std::vector<std::string>& extensions, 151 const ErrorCallbackType& errorCallback, 152 const LinkCallbackType& linkCallback) 153 { 154 std::error_code ec; 155 std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory, 156 ec); 157 if (ec) 158 { 159 makeCallback(errorCallback, hostFirmwareDirectory, ec); 160 return; 161 } 162 163 // Create a symlink from HBB to the corresponding LID file if it exists 164 static const auto hbbLid = "81e0065a.lid"; 165 auto hbbLidPath = hostFirmwareDirectory / hbbLid; 166 if (std::filesystem::exists(hbbLidPath)) 167 { 168 static const auto hbbName = "HBB"; 169 auto hbbLinkPath = hostFirmwareDirectory / hbbName; 170 makeCallback(linkCallback, hbbLid, hbbLinkPath, errorCallback); 171 } 172 173 for (; directoryIterator != std::filesystem::end(directoryIterator); 174 directoryIterator.increment(ec)) 175 { 176 const auto& file = directoryIterator->path(); 177 if (ec) 178 { 179 makeCallback(errorCallback, file, ec); 180 // quit here if the increment call failed otherwise the loop may 181 // never finish 182 break; 183 } 184 185 if (std::find(extensions.begin(), extensions.end(), file.extension()) == 186 extensions.end()) 187 { 188 // this file doesn't have an extension or doesn't match any of the 189 // provided extensions. 190 continue; 191 } 192 193 auto linkPath(file.parent_path().append( 194 static_cast<const std::string&>(file.stem()))); 195 196 makeCallback(linkCallback, file.filename(), linkPath, errorCallback); 197 } 198 } 199 200 /** 201 * @brief Parse the elements json file and construct a string with the data to 202 * be used to update the bios attribute table. 203 * 204 * @param[in] elementsJsonFilePath - The path to the host firmware json file. 205 * @param[in] extensions - The extensions of the firmware blob files. 206 */ 207 std::string getBiosAttrStr(const std::filesystem::path& elementsJsonFilePath, 208 const std::vector<std::string>& extensions) 209 { 210 std::string biosAttrStr{}; 211 212 std::ifstream jsonFile(elementsJsonFilePath.c_str()); 213 if (!jsonFile) 214 { 215 return {}; 216 } 217 218 std::map<std::string, std::string> attr; 219 auto data = nlohmann::json::parse(jsonFile, nullptr, false); 220 if (data.is_discarded()) 221 { 222 log<level::ERR>("Error parsing JSON file", 223 entry("FILE=%s", elementsJsonFilePath.c_str())); 224 return {}; 225 } 226 227 // .get requires a non-const iterator 228 for (auto& iter : data["lids"]) 229 { 230 std::string name{}; 231 std::string lid{}; 232 233 try 234 { 235 name = iter["element_name"].get<std::string>(); 236 lid = iter["short_lid_name"].get<std::string>(); 237 } 238 catch (std::exception& e) 239 { 240 // Possibly the element or lid name field was not found 241 log<level::ERR>("Error reading JSON field", 242 entry("FILE=%s", elementsJsonFilePath.c_str()), 243 entry("ERROR=%s", e.what())); 244 continue; 245 } 246 247 // The elements with the ipl extension have higher priority. Therefore 248 // Use operator[] to overwrite value if an entry for it already exists. 249 // Ex: if the JSON contains an entry A.P10 followed by A.P10.iplTime, 250 // the lid value for the latter one will be overwrite the value of the 251 // first one. 252 constexpr auto iplExtension = ".iplTime"; 253 std::filesystem::path path(name); 254 if (path.extension() == iplExtension) 255 { 256 // Some elements have an additional extension, ex: .P10.iplTime 257 // Strip off the ipl extension with stem(), then check if there is 258 // an additional extension with extension(). 259 if (!path.stem().extension().empty()) 260 { 261 // Check if the extension matches the extensions for this system 262 if (std::find(extensions.begin(), extensions.end(), 263 path.stem().extension()) == extensions.end()) 264 { 265 continue; 266 } 267 } 268 // Get the element name without extensions by calling stem() twice 269 // since stem() returns the base name if no periods are found. 270 // Therefore both "element.P10" and "element.P10.iplTime" would 271 // become "element". 272 attr[path.stem().stem()] = lid; 273 continue; 274 } 275 276 // Process all other extensions. The extension should match the list of 277 // supported extensions for this system. Use .insert() to only add 278 // entries that do not exist, so to not overwrite the values that may 279 // had been added that had the ipl extension. 280 if (std::find(extensions.begin(), extensions.end(), path.extension()) != 281 extensions.end()) 282 { 283 attr.insert({path.stem(), lid}); 284 } 285 } 286 for (const auto& a : attr) 287 { 288 // Build the bios attribute string with format: 289 // "element1=lid1,element2=lid2,elementN=lidN," 290 biosAttrStr += a.first + "=" + a.second + ","; 291 } 292 293 return biosAttrStr; 294 } 295 296 /** 297 * @brief Set the bios attribute table with details of the host firmware data 298 * for this system. 299 * 300 * @param[in] elementsJsonFilePath - The path to the host firmware json file. 301 * @param[in] extentions - The extensions of the firmware blob files. 302 */ 303 void setBiosAttr(const std::filesystem::path& elementsJsonFilePath, 304 const std::vector<std::string>& extensions) 305 { 306 auto biosAttrStr = getBiosAttrStr(elementsJsonFilePath, extensions); 307 308 constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager"; 309 constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager"; 310 constexpr auto dbusAttrName = "hb_lid_ids"; 311 constexpr auto dbusAttrType = 312 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String"; 313 314 using PendingAttributesType = std::vector<std::pair< 315 std::string, std::tuple<std::string, std::variant<std::string>>>>; 316 PendingAttributesType pendingAttributes; 317 pendingAttributes.emplace_back(std::make_pair( 318 dbusAttrName, std::make_tuple(dbusAttrType, biosAttrStr))); 319 320 auto bus = sdbusplus::bus::new_default(); 321 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 322 MAPPER_INTERFACE, "GetObject"); 323 method.append(biosConfigPath, std::vector<std::string>({biosConfigIntf})); 324 std::vector<std::pair<std::string, std::vector<std::string>>> response; 325 try 326 { 327 auto reply = bus.call(method); 328 reply.read(response); 329 if (response.empty()) 330 { 331 log<level::ERR>("Error reading mapper response", 332 entry("PATH=%s", biosConfigPath), 333 entry("INTERFACE=%s", biosConfigIntf)); 334 return; 335 } 336 auto method = bus.new_method_call((response.begin()->first).c_str(), 337 biosConfigPath, 338 SYSTEMD_PROPERTY_INTERFACE, "Set"); 339 method.append(biosConfigIntf, "PendingAttributes", 340 std::variant<PendingAttributesType>(pendingAttributes)); 341 bus.call(method); 342 } 343 catch (const sdbusplus::exception::SdBusError& e) 344 { 345 log<level::ERR>("Error setting the bios attribute", 346 entry("ERROR=%s", e.what()), 347 entry("ATTRIBUTE=%s", dbusAttrName)); 348 return; 349 } 350 } 351 352 /** 353 * @brief Make callbacks on 354 * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances. 355 * 356 * Look for an instance of 357 * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided 358 * argument and if found, issue the provided callback. 359 * 360 * @param[in] interfacesAndProperties the interfaces in which to look for an 361 * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem 362 * @param[in] callback the user callback to make if 363 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in 364 * interfacesAndProperties 365 * @return true if interfacesAndProperties contained an instance of 366 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise 367 */ 368 bool maybeCall(const std::map<std::string, 369 std::map<std::string, 370 std::variant<std::vector<std::string>>>>& 371 interfacesAndProperties, 372 const MaybeCallCallbackType& callback) 373 { 374 using namespace std::string_literals; 375 376 static const auto interfaceName = 377 "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s; 378 auto interfaceIterator = interfacesAndProperties.find(interfaceName); 379 if (interfaceIterator == interfacesAndProperties.cend()) 380 { 381 // IBMCompatibleSystem interface not found, so instruct the caller to 382 // keep waiting or try again later. 383 return false; 384 } 385 auto propertyIterator = interfaceIterator->second.find("Names"s); 386 if (propertyIterator == interfaceIterator->second.cend()) 387 { 388 // The interface exists but the property doesn't. This is a bug in the 389 // IBMCompatibleSystem implementation. The caller should not try 390 // again. 391 std::cerr << "Names property not implemented on " << interfaceName 392 << "\n"; 393 return true; 394 } 395 396 const auto& ibmCompatibleSystem = 397 std::get<std::vector<std::string>>(propertyIterator->second); 398 if (callback) 399 { 400 callback(ibmCompatibleSystem); 401 } 402 403 // IBMCompatibleSystem found and callback issued. 404 return true; 405 } 406 407 /** 408 * @brief Make callbacks on 409 * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances. 410 * 411 * Look for an instance of 412 * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided 413 * argument and if found, issue the provided callback. 414 * 415 * @param[in] message the DBus message in which to look for an instance of 416 * xyz.openbmc_project.Configuration.IBMCompatibleSystem 417 * @param[in] callback the user callback to make if 418 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in 419 * message 420 * @return true if message contained an instance of 421 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise 422 */ 423 bool maybeCallMessage(sdbusplus::message::message& message, 424 const MaybeCallCallbackType& callback) 425 { 426 std::map<std::string, 427 std::map<std::string, std::variant<std::vector<std::string>>>> 428 interfacesAndProperties; 429 sdbusplus::message::object_path _; 430 message.read(_, interfacesAndProperties); 431 return maybeCall(interfacesAndProperties, callback); 432 } 433 434 /** 435 * @brief Determine system support for host firmware well-known names. 436 * 437 * Using the provided extensionMap and 438 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if 439 * well-known names for host firmare blob files are necessary and if so, create 440 * them. 441 * 442 * @param[in] extensionMap a map of 443 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 444 * file extensions. 445 * @param[in] hostFirmwareDirectory The directory in which findLinks should 446 * look for host firmware blob files that need well-known names. 447 * @param[in] ibmCompatibleSystem The names property of an instance of 448 * xyz.openbmc_project.Configuration.IBMCompatibleSystem 449 * @param[in] errorCallback A callback made in the event of filesystem errors. 450 */ 451 void maybeMakeLinks( 452 const std::map<std::string, std::vector<std::string>>& extensionMap, 453 const std::filesystem::path& hostFirmwareDirectory, 454 const std::vector<std::string>& ibmCompatibleSystem, 455 const ErrorCallbackType& errorCallback) 456 { 457 std::vector<std::string> extensions; 458 if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 459 extensions)) 460 { 461 findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink); 462 } 463 } 464 465 /** 466 * @brief Determine system support for updating the bios attribute table. 467 * 468 * Using the provided extensionMap and 469 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if the bios 470 * attribute table needs to be updated. 471 * 472 * @param[in] extensionMap a map of 473 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 474 * file extensions. 475 * @param[in] elementsJsonFilePath The file path to the json file 476 * @param[in] ibmCompatibleSystem The names property of an instance of 477 * xyz.openbmc_project.Configuration.IBMCompatibleSystem 478 */ 479 void maybeSetBiosAttr( 480 const std::map<std::string, std::vector<std::string>>& extensionMap, 481 const std::filesystem::path& elementsJsonFilePath, 482 const std::vector<std::string>& ibmCompatibleSystem) 483 { 484 std::vector<std::string> extensions; 485 if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 486 extensions)) 487 { 488 setBiosAttr(elementsJsonFilePath, extensions); 489 } 490 } 491 492 /** 493 * @brief process host firmware 494 * 495 * Allocate a callback context and register for DBus.ObjectManager Interfaces 496 * added signals from entity manager. 497 * 498 * Check the current entity manager object tree for a 499 * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity 500 * manager will be dbus activated if it is not running). If one is found, 501 * determine if symlinks need to be created and create them. Instruct the 502 * program event loop to exit. 503 * 504 * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is 505 * found return the callback context to main, where the program will sleep 506 * until the callback is invoked one or more times and instructs the program 507 * event loop to exit when 508 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added. 509 * 510 * @param[in] bus a DBus client connection 511 * @param[in] extensionMap a map of 512 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 513 * file extensions. 514 * @param[in] hostFirmwareDirectory The directory in which processHostFirmware 515 * should look for blob files. 516 * @param[in] errorCallback A callback made in the event of filesystem errors. 517 * @param[in] loop a program event loop 518 * @return nullptr if an instance of 519 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a 520 * pointer to an sdbusplus match object. 521 */ 522 std::shared_ptr<void> processHostFirmware( 523 sdbusplus::bus::bus& bus, 524 std::map<std::string, std::vector<std::string>> extensionMap, 525 std::filesystem::path hostFirmwareDirectory, 526 ErrorCallbackType errorCallback, sdeventplus::Event& loop) 527 { 528 // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't 529 // be transfered to the match callback because they are needed in the non 530 // async part of this function below, so they need to be moved to the heap. 531 auto pExtensionMap = 532 std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 533 auto pHostFirmwareDirectory = 534 std::make_shared<decltype(hostFirmwareDirectory)>( 535 std::move(hostFirmwareDirectory)); 536 auto pErrorCallback = 537 std::make_shared<decltype(errorCallback)>(std::move(errorCallback)); 538 539 // register for a callback in case the IBMCompatibleSystem interface has 540 // not yet been published by entity manager. 541 auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>( 542 bus, 543 sdbusplus::bus::match::rules::interfacesAdded() + 544 sdbusplus::bus::match::rules::sender( 545 "xyz.openbmc_project.EntityManager"), 546 [pExtensionMap, pHostFirmwareDirectory, pErrorCallback, 547 &loop](auto& message) { 548 // bind the extension map, host firmware directory, and error 549 // callback to the maybeMakeLinks function. 550 auto maybeMakeLinksWithArgsBound = 551 std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 552 std::cref(*pHostFirmwareDirectory), 553 std::placeholders::_1, std::cref(*pErrorCallback)); 554 555 // if the InterfacesAdded message contains an an instance of 556 // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to 557 // see if links are necessary on this system and if so, create 558 // them. 559 if (maybeCallMessage(message, maybeMakeLinksWithArgsBound)) 560 { 561 // The IBMCompatibleSystem interface was found and the links 562 // were created if applicable. Instruct the event loop / 563 // subcommand to exit. 564 loop.exit(0); 565 } 566 }); 567 568 // now that we'll get a callback in the event of an InterfacesAdded signal 569 // (potentially containing 570 // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity 571 // manager if it isn't running and enumerate its objects 572 auto getManagedObjects = bus.new_method_call( 573 "xyz.openbmc_project.EntityManager", "/", 574 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 575 std::map<std::string, 576 std::map<std::string, std::variant<std::vector<std::string>>>> 577 interfacesAndProperties; 578 std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 579 objects; 580 try 581 { 582 auto reply = bus.call(getManagedObjects); 583 reply.read(objects); 584 } 585 catch (const sdbusplus::exception::SdBusError& e) 586 { 587 // Error querying the EntityManager interface. Return the match to have 588 // the callback run if/when the interface appears in D-Bus. 589 return interfacesAddedMatch; 590 } 591 592 // bind the extension map, host firmware directory, and error callback to 593 // the maybeMakeLinks function. 594 auto maybeMakeLinksWithArgsBound = 595 std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 596 std::cref(*pHostFirmwareDirectory), std::placeholders::_1, 597 std::cref(*pErrorCallback)); 598 599 for (const auto& pair : objects) 600 { 601 std::tie(std::ignore, interfacesAndProperties) = pair; 602 // if interfacesAndProperties contains an an instance of 603 // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see 604 // if links are necessary on this system and if so, create them 605 if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound)) 606 { 607 // The IBMCompatibleSystem interface is already on the bus and the 608 // links were created if applicable. Instruct the event loop to 609 // exit. 610 loop.exit(0); 611 // The match object isn't needed anymore, so destroy it on return. 612 return nullptr; 613 } 614 } 615 616 // The IBMCompatibleSystem interface has not yet been published. Move 617 // ownership of the match callback to the caller. 618 return interfacesAddedMatch; 619 } 620 621 /** 622 * @brief Update the Bios Attribute Table 623 * 624 * If an instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is 625 * found, update the Bios Attribute Table with the appropriate host firmware 626 * data. 627 * 628 * @param[in] bus - D-Bus client connection. 629 * @param[in] extensionMap - Map of IBMCompatibleSystem names and host firmware 630 * file extensions. 631 * @param[in] elementsJsonFilePath - The Path to the json file 632 * @param[in] loop - Program event loop. 633 * @return nullptr 634 */ 635 std::shared_ptr<void> updateBiosAttrTable( 636 sdbusplus::bus::bus& bus, 637 std::map<std::string, std::vector<std::string>> extensionMap, 638 std::filesystem::path elementsJsonFilePath, sdeventplus::Event& loop) 639 { 640 auto pExtensionMap = 641 std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 642 auto pElementsJsonFilePath = 643 std::make_shared<decltype(elementsJsonFilePath)>( 644 std::move(elementsJsonFilePath)); 645 646 auto getManagedObjects = bus.new_method_call( 647 "xyz.openbmc_project.EntityManager", "/", 648 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 649 std::map<std::string, 650 std::map<std::string, std::variant<std::vector<std::string>>>> 651 interfacesAndProperties; 652 std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 653 objects; 654 try 655 { 656 auto reply = bus.call(getManagedObjects); 657 reply.read(objects); 658 } 659 catch (const sdbusplus::exception::SdBusError& e) 660 {} 661 662 auto maybeSetAttrWithArgsBound = 663 std::bind(maybeSetBiosAttr, std::cref(*pExtensionMap), 664 std::cref(*pElementsJsonFilePath), std::placeholders::_1); 665 666 for (const auto& pair : objects) 667 { 668 std::tie(std::ignore, interfacesAndProperties) = pair; 669 if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound)) 670 { 671 break; 672 } 673 } 674 675 loop.exit(0); 676 return nullptr; 677 } 678 679 } // namespace process_hostfirmware 680 } // namespace functions 681