1 #pragma once 2 3 #include "constants.hpp" 4 #include "exceptions.hpp" 5 #include "logger.hpp" 6 #include "types.hpp" 7 8 #include <chrono> 9 10 namespace vpd 11 { 12 /** 13 * @brief The namespace defines utlity methods for generic D-Bus operations. 14 */ 15 namespace dbusUtility 16 { 17 18 /** 19 * @brief An API to get Map of service and interfaces for an object path. 20 * 21 * The API returns a Map of service name and interfaces for a given pair of 22 * object path and interface list. It can be used to determine service name 23 * which implemets a particular object path and interface. 24 * 25 * Note: It will be caller's responsibility to check for empty map returned and 26 * generate appropriate error. 27 * 28 * @param [in] objectPath - Object path under the service. 29 * @param [in] interfaces - Array of interface(s). 30 * @return - A Map of service name to object to interface(s), if success. 31 * If failed, empty map. 32 */ 33 inline types::MapperGetObject getObjectMap(const std::string& objectPath, 34 std::span<const char*> interfaces) 35 { 36 types::MapperGetObject getObjectMap; 37 38 // interface list is optional argument, hence no check required. 39 if (objectPath.empty()) 40 { 41 logging::logMessage("Path value is empty, invalid call to GetObject"); 42 return getObjectMap; 43 } 44 45 try 46 { 47 auto bus = sdbusplus::bus::new_default(); 48 auto method = bus.new_method_call( 49 "xyz.openbmc_project.ObjectMapper", 50 "/xyz/openbmc_project/object_mapper", 51 "xyz.openbmc_project.ObjectMapper", "GetObject"); 52 53 method.append(objectPath, interfaces); 54 auto result = bus.call(method); 55 result.read(getObjectMap); 56 } 57 catch (const sdbusplus::exception::SdBusError& e) 58 { 59 // logging::logMessage(e.what()); 60 return getObjectMap; 61 } 62 63 return getObjectMap; 64 } 65 66 /** 67 * @brief An API to get property map for an interface. 68 * 69 * This API returns a map of property and its value with respect to a particular 70 * interface. 71 * 72 * Note: It will be caller's responsibility to check for empty map returned and 73 * generate appropriate error. 74 * 75 * @param[in] i_service - Service name. 76 * @param[in] i_objectPath - object path. 77 * @param[in] i_interface - Interface, for the properties to be listed. 78 * 79 * @return - A map of property and value of an interface, if success. 80 * if failed, empty map. 81 */ 82 inline types::PropertyMap getPropertyMap(const std::string& i_service, 83 const std::string& i_objectPath, 84 const std::string& i_interface) 85 { 86 types::PropertyMap l_propertyValueMap; 87 if (i_service.empty() || i_objectPath.empty() || i_interface.empty()) 88 { 89 logging::logMessage("Invalid parameters to get property map"); 90 return l_propertyValueMap; 91 } 92 93 try 94 { 95 auto l_bus = sdbusplus::bus::new_default(); 96 auto l_method = 97 l_bus.new_method_call(i_service.c_str(), i_objectPath.c_str(), 98 "org.freedesktop.DBus.Properties", "GetAll"); 99 l_method.append(i_interface); 100 auto l_result = l_bus.call(l_method); 101 l_result.read(l_propertyValueMap); 102 } 103 catch (const sdbusplus::exception::SdBusError& l_ex) 104 { 105 logging::logMessage(l_ex.what()); 106 } 107 108 return l_propertyValueMap; 109 } 110 111 /** 112 * @brief API to get object subtree from D-bus. 113 * 114 * The API returns the map of object, services and interfaces in the 115 * subtree that implement a certain interface. If no interfaces are provided 116 * then all the objects, services and interfaces under the subtree will 117 * be returned. 118 * 119 * Note: Depth can be 0 and interfaces can be null. 120 * It will be caller's responsibility to check for empty vector returned 121 * and generate appropriate error. 122 * 123 * @param[in] i_objectPath - Path to search for an interface. 124 * @param[in] i_depth - Maximum depth of the tree to search. 125 * @param[in] i_interfaces - List of interfaces to search. 126 * 127 * @return - A map of object and its related services and interfaces, if 128 * success. If failed, empty map. 129 */ 130 131 inline types::MapperGetSubTree getObjectSubTree( 132 const std::string& i_objectPath, const int& i_depth, 133 const std::vector<std::string>& i_interfaces) 134 { 135 types::MapperGetSubTree l_subTreeMap; 136 137 if (i_objectPath.empty()) 138 { 139 logging::logMessage("Object path is empty."); 140 return l_subTreeMap; 141 } 142 143 try 144 { 145 auto l_bus = sdbusplus::bus::new_default(); 146 auto l_method = l_bus.new_method_call( 147 constants::objectMapperService, constants::objectMapperPath, 148 constants::objectMapperInf, "GetSubTree"); 149 l_method.append(i_objectPath, i_depth, i_interfaces); 150 auto l_result = l_bus.call(l_method); 151 l_result.read(l_subTreeMap); 152 } 153 catch (const sdbusplus::exception::SdBusError& l_ex) 154 { 155 logging::logMessage(l_ex.what()); 156 } 157 158 return l_subTreeMap; 159 } 160 161 /** 162 * @brief An API to read property from Dbus. 163 * 164 * The caller of the API needs to validate the validatity and correctness of the 165 * type and value of data returned. The API will just fetch and retun the data 166 * without any data validation. 167 * 168 * Note: It will be caller's responsibility to check for empty value returned 169 * and generate appropriate error if required. 170 * 171 * @param [in] serviceName - Name of the Dbus service. 172 * @param [in] objectPath - Object path under the service. 173 * @param [in] interface - Interface under which property exist. 174 * @param [in] property - Property whose value is to be read. 175 * @return - Value read from Dbus, if success. 176 * If failed, empty variant. 177 */ 178 inline types::DbusVariantType readDbusProperty( 179 const std::string& serviceName, const std::string& objectPath, 180 const std::string& interface, const std::string& property) 181 { 182 types::DbusVariantType propertyValue; 183 184 // Mandatory fields to make a read dbus call. 185 if (serviceName.empty() || objectPath.empty() || interface.empty() || 186 property.empty()) 187 { 188 logging::logMessage( 189 "One of the parameter to make Dbus read call is empty."); 190 return propertyValue; 191 } 192 193 try 194 { 195 auto bus = sdbusplus::bus::new_default(); 196 auto method = 197 bus.new_method_call(serviceName.c_str(), objectPath.c_str(), 198 "org.freedesktop.DBus.Properties", "Get"); 199 method.append(interface, property); 200 201 auto result = bus.call(method); 202 result.read(propertyValue); 203 } 204 catch (const sdbusplus::exception::SdBusError& e) 205 { 206 return propertyValue; 207 } 208 return propertyValue; 209 } 210 211 /** 212 * @brief An API to write property on Dbus. 213 * 214 * The caller of this API needs to handle exception thrown by this method to 215 * identify any write failure. The API in no other way indicate write failure 216 * to the caller. 217 * 218 * @param [in] serviceName - Name of the Dbus service. 219 * @param [in] objectPath - Object path under the service. 220 * @param [in] interface - Interface under which property exist. 221 * @param [in] property - Property whose value is to be written. 222 * @param [in] propertyValue - The value to be written. 223 * @return True if write on DBus is success, false otherwise. 224 */ 225 inline bool writeDbusProperty( 226 const std::string& serviceName, const std::string& objectPath, 227 const std::string& interface, const std::string& property, 228 const types::DbusVariantType& propertyValue) 229 { 230 try 231 { 232 // Mandatory fields to make a write dbus call. 233 if (serviceName.empty() || objectPath.empty() || interface.empty() || 234 property.empty()) 235 { 236 throw std::runtime_error("Dbus write failed, Parameter empty"); 237 } 238 239 auto bus = sdbusplus::bus::new_default(); 240 auto method = 241 bus.new_method_call(serviceName.c_str(), objectPath.c_str(), 242 "org.freedesktop.DBus.Properties", "Set"); 243 method.append(interface, property, propertyValue); 244 bus.call(method); 245 246 return true; 247 } 248 catch (const std::exception& l_ex) 249 { 250 logging::logMessage( 251 "DBus write failed, error: " + std::string(l_ex.what())); 252 return false; 253 } 254 } 255 256 /** 257 * @brief API to publish data on PIM 258 * 259 * The API calls notify on PIM object to publlish VPD. 260 * 261 * @param[in] objectMap - Object, its interface and data. 262 * @return bool - Status of call to PIM notify. 263 */ 264 inline bool callPIM(types::ObjectMap&& objectMap) 265 { 266 try 267 { 268 for (const auto& l_objectKeyValue : objectMap) 269 { 270 if (l_objectKeyValue.first.str.find(constants::pimPath, 0) != 271 std::string::npos) 272 { 273 auto l_nodeHandle = objectMap.extract(l_objectKeyValue.first); 274 l_nodeHandle.key() = l_nodeHandle.key().str.replace( 275 0, std::strlen(constants::pimPath), ""); 276 objectMap.insert(std::move(l_nodeHandle)); 277 } 278 } 279 280 auto bus = sdbusplus::bus::new_default(); 281 auto pimMsg = 282 bus.new_method_call(constants::pimServiceName, constants::pimPath, 283 constants::pimIntf, "Notify"); 284 pimMsg.append(std::move(objectMap)); 285 bus.call(pimMsg); 286 } 287 catch (const sdbusplus::exception::SdBusError& e) 288 { 289 return false; 290 } 291 return true; 292 } 293 294 /** 295 * @brief API to check if a D-Bus service is running or not. 296 * 297 * Any failure in calling the method "NameHasOwner" implies that the service is 298 * not in a running state. Hence the API returns false in case of any exception 299 * as well. 300 * 301 * @param[in] i_serviceName - D-Bus service name whose status is to be checked. 302 * @return bool - True if the service is running, false otherwise. 303 */ 304 inline bool isServiceRunning(const std::string& i_serviceName) 305 { 306 bool l_retVal = false; 307 308 try 309 { 310 auto l_bus = sdbusplus::bus::new_default(); 311 auto l_method = l_bus.new_method_call( 312 "org.freedesktop.DBus", "/org/freedesktop/DBus", 313 "org.freedesktop.DBus", "NameHasOwner"); 314 l_method.append(i_serviceName); 315 316 l_bus.call(l_method).read(l_retVal); 317 } 318 catch (const sdbusplus::exception::SdBusError& l_ex) 319 { 320 logging::logMessage( 321 "Call to check service status failed with exception: " + 322 std::string(l_ex.what())); 323 } 324 325 return l_retVal; 326 } 327 328 /** 329 * @brief API to call "GetAttribute" method uner BIOS manager. 330 * 331 * The API reads the given attribuute from BIOS and returns a tuple of both 332 * current as well as pending value for that attribute. 333 * The API return only the current attribute value if found. 334 * API returns an empty variant of type BiosAttributeCurrentValue in case of any 335 * error. 336 * 337 * @param[in] i_attributeName - Attribute to be read. 338 * @return Tuple of PLDM attribute Type, current attribute value and pending 339 * attribute value. 340 */ 341 inline types::BiosAttributeCurrentValue biosGetAttributeMethodCall( 342 const std::string& i_attributeName) noexcept 343 { 344 types::BiosGetAttrRetType l_attributeVal; 345 try 346 { 347 auto l_bus = sdbusplus::bus::new_default(); 348 auto l_method = l_bus.new_method_call( 349 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 350 constants::biosConfigMgrInterface, "GetAttribute"); 351 l_method.append(i_attributeName); 352 353 auto l_result = l_bus.call(l_method); 354 l_result.read(std::get<0>(l_attributeVal), std::get<1>(l_attributeVal), 355 std::get<2>(l_attributeVal)); 356 } 357 catch (const sdbusplus::exception::SdBusError& l_ex) 358 { 359 logging::logMessage( 360 "Failed to read BIOS Attribute: " + i_attributeName + 361 " due to error " + std::string(l_ex.what())); 362 363 // TODO: Log an informational PEL here. 364 } 365 366 return std::get<1>(l_attributeVal); 367 } 368 369 /** 370 * @brief API to check if Chassis is powered on. 371 * 372 * This API queries Phosphor Chassis State Manager to know whether 373 * Chassis is powered on. 374 * 375 * @return true if chassis is powered on, false otherwise 376 */ 377 inline bool isChassisPowerOn() 378 { 379 auto powerState = dbusUtility::readDbusProperty( 380 "xyz.openbmc_project.State.Chassis", 381 "/xyz/openbmc_project/state/chassis0", 382 "xyz.openbmc_project.State.Chassis", "CurrentPowerState"); 383 384 if (auto curPowerState = std::get_if<std::string>(&powerState)) 385 { 386 if ("xyz.openbmc_project.State.Chassis.PowerState.On" == *curPowerState) 387 { 388 return true; 389 } 390 return false; 391 } 392 393 /* 394 TODO: Add PEL. 395 Callout: Firmware callout 396 Type: Informational 397 Description: Chassis state can't be determined, defaulting to chassis 398 off. : e.what() 399 */ 400 return false; 401 } 402 403 /** 404 * @brief API to check if host is in running state. 405 * 406 * This API reads the current host state from D-bus and returns true if the host 407 * is running. 408 * 409 * @return true if host is in running state. false otherwise. 410 */ 411 inline bool isHostRunning() 412 { 413 const auto l_hostState = dbusUtility::readDbusProperty( 414 constants::hostService, constants::hostObjectPath, 415 constants::hostInterface, "CurrentHostState"); 416 417 if (const auto l_currHostState = std::get_if<std::string>(&l_hostState)) 418 { 419 if (*l_currHostState == constants::hostRunningState) 420 { 421 return true; 422 } 423 } 424 425 return false; 426 } 427 428 /** 429 * @brief API to check if BMC is in ready state. 430 * 431 * This API reads the current state of BMC from D-bus and returns true if BMC is 432 * in ready state. 433 * 434 * @return true if BMC is ready, false otherwise. 435 */ 436 inline bool isBMCReady() 437 { 438 const auto l_bmcState = dbusUtility::readDbusProperty( 439 constants::bmcStateService, constants::bmcZeroStateObject, 440 constants::bmcStateInterface, constants::currentBMCStateProperty); 441 442 if (const auto l_currBMCState = std::get_if<std::string>(&l_bmcState)) 443 { 444 if (*l_currBMCState == constants::bmcReadyState) 445 { 446 return true; 447 } 448 } 449 450 return false; 451 } 452 453 /** 454 * @brief An API to enable BMC reboot guard 455 * 456 * This API does a D-Bus method call to enable BMC reboot guard. 457 * 458 * @return On success, returns 0, otherwise returns -1. 459 */ 460 inline int EnableRebootGuard() noexcept 461 { 462 int l_rc{constants::FAILURE}; 463 try 464 { 465 auto l_bus = sdbusplus::bus::new_default(); 466 auto l_method = l_bus.new_method_call( 467 constants::systemdService, constants::systemdObjectPath, 468 constants::systemdManagerInterface, "StartUnit"); 469 l_method.append("reboot-guard-enable.service", "replace"); 470 l_bus.call_noreply(l_method); 471 l_rc = constants::SUCCESS; 472 } 473 catch (const sdbusplus::exception::SdBusError& l_ex) 474 { 475 std::string l_errMsg = 476 "D-Bus call to enable BMC reboot guard failed for reason: "; 477 l_errMsg += l_ex.what(); 478 479 logging::logMessage(l_errMsg); 480 } 481 return l_rc; 482 } 483 484 /** 485 * @brief An API to disable BMC reboot guard 486 * 487 * This API disables BMC reboot guard. This API has an inbuilt re-try mechanism. 488 * If Disable Reboot Guard fails, this API attempts to Disable Reboot Guard for 489 * 3 more times at an interval of 333ms. 490 * 491 * @return On success, returns 0, otherwise returns -1. 492 */ 493 inline int DisableRebootGuard() noexcept 494 { 495 int l_rc{constants::FAILURE}; 496 497 // A lambda which executes the DBus call to disable BMC reboot guard. 498 auto l_executeDisableRebootGuard = []() -> int { 499 int l_dBusCallRc{constants::FAILURE}; 500 try 501 { 502 auto l_bus = sdbusplus::bus::new_default(); 503 auto l_method = l_bus.new_method_call( 504 constants::systemdService, constants::systemdObjectPath, 505 constants::systemdManagerInterface, "StartUnit"); 506 l_method.append("reboot-guard-disable.service", "replace"); 507 l_bus.call_noreply(l_method); 508 l_dBusCallRc = constants::SUCCESS; 509 } 510 catch (const sdbusplus::exception::SdBusError& l_ex) 511 {} 512 return l_dBusCallRc; 513 }; 514 515 if (constants::FAILURE == l_executeDisableRebootGuard()) 516 { 517 std::function<void()> l_retryDisableRebootGuard; 518 519 // A lambda which tries to disable BMC reboot guard for 3 times at an 520 // interval of 333 ms. 521 l_retryDisableRebootGuard = [&]() { 522 constexpr int MAX_RETRIES{3}; 523 static int l_numRetries{0}; 524 525 if (l_numRetries < MAX_RETRIES) 526 { 527 l_numRetries++; 528 if (constants::FAILURE == l_executeDisableRebootGuard()) 529 { 530 // sleep for 333ms before next retry. This is just a random 531 // value so that 3 re-tries * 333ms takes ~1 second in the 532 // worst case. 533 const std::chrono::milliseconds l_sleepTime{333}; 534 std::this_thread::sleep_for(l_sleepTime); 535 l_retryDisableRebootGuard(); 536 } 537 else 538 { 539 l_numRetries = 0; 540 l_rc = constants::SUCCESS; 541 } 542 } 543 else 544 { 545 // Failed to Disable Reboot Guard even after 3 retries. 546 logging::logMessage("Failed to Disable Reboot Guard after " + 547 std::to_string(MAX_RETRIES) + " re-tries"); 548 l_numRetries = 0; 549 } 550 }; 551 552 l_retryDisableRebootGuard(); 553 } 554 else 555 { 556 l_rc = constants::SUCCESS; 557 } 558 return l_rc; 559 } 560 561 /** 562 * @brief API to notify FRU VPD Collection status. 563 * 564 * This API uses PIM's Notify method to update the given FRU VPD collection 565 * status on D-bus. 566 * 567 * @param[in] i_inventoryPath - D-bus inventory path 568 * @param[in] i_fruCollectionStatus - FRU VPD collection status. 569 * 570 * @return true if update succeeds, false otherwise. 571 */ 572 inline bool notifyFRUCollectionStatus(const std::string& i_inventoryPath, 573 const std::string& i_fruCollectionStatus) 574 { 575 types::ObjectMap l_objectMap; 576 types::InterfaceMap l_interfaceMap; 577 types::PropertyMap l_propertyMap; 578 579 l_propertyMap.emplace("Status", i_fruCollectionStatus); 580 l_interfaceMap.emplace(constants::vpdCollectionInterface, l_propertyMap); 581 l_objectMap.emplace(i_inventoryPath, l_interfaceMap); 582 583 if (!dbusUtility::callPIM(std::move(l_objectMap))) 584 { 585 return false; 586 } 587 588 return true; 589 } 590 591 /** 592 * @brief API to read IM keyword from Dbus. 593 * 594 * @return IM value read from Dbus, Empty in case of any error. 595 */ 596 inline types::BinaryVector getImFromDbus() 597 { 598 const auto& l_retValue = dbusUtility::readDbusProperty( 599 constants::pimServiceName, constants::systemVpdInvPath, 600 constants::vsbpInf, constants::kwdIM); 601 602 auto l_imValue = std::get_if<types::BinaryVector>(&l_retValue); 603 if (!l_imValue || (*l_imValue).size() != constants::VALUE_4) 604 { 605 return types::BinaryVector{}; 606 } 607 608 return *l_imValue; 609 } 610 611 /** 612 * @brief API to return prefix of functional firmware image. 613 * 614 * Every functional image belongs to a series which is denoted by the first two 615 * characters of the image name. The API extracts that and returns it to the 616 * caller. 617 * 618 * @return Two character string, empty string in case of any error. 619 */ 620 inline std::string getImagePrefix() 621 { 622 try 623 { 624 types::DbusVariantType l_retVal = readDbusProperty( 625 constants::objectMapperService, constants::functionalImageObjPath, 626 constants::associationInterface, "endpoints"); 627 628 auto l_listOfFunctionalPath = 629 std::get_if<std::vector<std::string>>(&l_retVal); 630 631 if (!l_listOfFunctionalPath || (*l_listOfFunctionalPath).empty()) 632 { 633 throw DbusException("failed to get functional image path."); 634 } 635 636 for (const auto& l_imagePath : *l_listOfFunctionalPath) 637 { 638 types::DbusVariantType l_retValPriority = 639 readDbusProperty(constants::imageUpdateService, l_imagePath, 640 constants::imagePrirotyInf, "Priority"); 641 642 auto l_imagePriority = std::get_if<uint8_t>(&l_retValPriority); 643 if (!l_imagePriority) 644 { 645 throw DbusException( 646 "failed to read functional image priority for path [" + 647 l_imagePath + "]"); 648 } 649 650 // only interested in running image. 651 if (*l_imagePriority != constants::VALUE_0) 652 { 653 continue; 654 } 655 656 types::DbusVariantType l_retExVer = readDbusProperty( 657 constants::imageUpdateService, l_imagePath, 658 constants::imageExtendedVerInf, "ExtendedVersion"); 659 660 auto l_imageExtendedVersion = std::get_if<std::string>(&l_retExVer); 661 if (!l_imageExtendedVersion) 662 { 663 throw DbusException( 664 "Unable to read extended version for the functional image [" + 665 l_imagePath + "]"); 666 } 667 668 if ((*l_imageExtendedVersion).empty() || 669 (*l_imageExtendedVersion).length() <= constants::VALUE_2) 670 { 671 throw DbusException("Invalid extended version read for path [" + 672 l_imagePath + "]"); 673 } 674 675 // return first two character from image name. 676 return (*l_imageExtendedVersion) 677 .substr(constants::VALUE_0, constants::VALUE_2); 678 } 679 throw std::runtime_error("No Image found with required priority."); 680 } 681 catch (const std::exception& l_ex) 682 { 683 logging::logMessage(l_ex.what()); 684 return std::string{}; 685 } 686 } 687 688 /** 689 * @brief API to read DBus present property for the given inventory. 690 * 691 * @param[in] i_invObjPath - Inventory path. 692 * @return Present property value, false in case of any error. 693 */ 694 inline bool isInventoryPresent(const std::string& i_invObjPath) 695 { 696 if (i_invObjPath.empty()) 697 { 698 return false; 699 } 700 701 const auto& l_retValue = 702 dbusUtility::readDbusProperty(constants::pimServiceName, i_invObjPath, 703 constants::inventoryItemInf, "Present"); 704 705 auto l_ptrPresence = std::get_if<bool>(&l_retValue); 706 if (!l_ptrPresence) 707 { 708 return false; 709 } 710 711 return (*l_ptrPresence); 712 } 713 714 /** 715 * @brief API to get list of sub tree paths for a given object path 716 * 717 * Given a DBus object path, this API returns a list of object paths under that 718 * object path in the DBus tree. This API calls DBus method GetSubTreePaths 719 * hosted by ObjectMapper DBus service. 720 * 721 * @param[in] i_objectPath - DBus object path. 722 * @param[in] i_depth - The maximum subtree depth for which results should be 723 * fetched. For unconstrained fetches use a depth of zero. 724 * @param[in] i_constrainingInterfaces - An array of result set constraining 725 * interfaces. 726 * 727 * @return On success, returns a std::vector<std::string> of object paths, 728 * else returns an empty vector. 729 * 730 * Note: The caller of this API should check for empty vector. 731 */ 732 inline std::vector<std::string> GetSubTreePaths( 733 const std::string i_objectPath, const int i_depth = 0, 734 const std::vector<std::string>& i_constrainingInterfaces = {}) noexcept 735 { 736 std::vector<std::string> l_objectPaths; 737 try 738 { 739 auto l_bus = sdbusplus::bus::new_default(); 740 auto l_method = l_bus.new_method_call( 741 constants::objectMapperService, constants::objectMapperPath, 742 constants::objectMapperInf, "GetSubTreePaths"); 743 744 l_method.append(i_objectPath, i_depth, i_constrainingInterfaces); 745 746 auto l_result = l_bus.call(l_method); 747 l_result.read(l_objectPaths); 748 } 749 catch (const sdbusplus::exception::SdBusError& l_ex) 750 { 751 logging::logMessage( 752 "Error while getting GetSubTreePaths for path [" + i_objectPath + 753 "], error: " + std::string(l_ex.what())); 754 } 755 return l_objectPaths; 756 } 757 758 /** 759 * @brief API to get Dbus service name for given connection identifier. 760 * 761 * @param[in] i_connectionId - Dbus connection ID. 762 * 763 * @return On success, returns the DBus service associated with given connection 764 * ID, empty string otherwise. 765 */ 766 inline std::string getServiceNameFromConnectionId( 767 const std::string& i_connectionId) noexcept 768 { 769 try 770 { 771 if (i_connectionId.empty()) 772 { 773 throw std::runtime_error("Empty connection ID"); 774 } 775 776 auto l_bus = sdbusplus::bus::new_default(); 777 778 // get PID corresponding to the connection ID 779 auto l_method = l_bus.new_method_call( 780 "org.freedesktop.DBus", "/org/freedesktop/DBus", 781 "org.freedesktop.DBus", "GetConnectionUnixProcessID"); 782 l_method.append(i_connectionId); 783 auto l_result = l_bus.call(l_method); 784 785 unsigned l_pid; 786 l_result.read(l_pid); 787 788 // use PID to get corresponding unit object path 789 l_method = l_bus.new_method_call( 790 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 791 "org.freedesktop.systemd1.Manager", "GetUnitByPID"); 792 l_method.append(l_pid); 793 l_result = l_bus.call(l_method); 794 795 sdbusplus::message::object_path l_unitObjectPath; 796 l_result.read(l_unitObjectPath); 797 798 // use unit object path to get service name 799 l_method = l_bus.new_method_call( 800 "org.freedesktop.systemd1", std::string(l_unitObjectPath).c_str(), 801 "org.freedesktop.DBus.Properties", "Get"); 802 l_method.append("org.freedesktop.systemd1.Unit", "Id"); 803 l_result = l_bus.call(l_method); 804 types::DbusVariantType l_serviceNameVar; 805 l_result.read(l_serviceNameVar); 806 807 if (auto l_serviceNameStr = std::get_if<std::string>(&l_serviceNameVar)) 808 { 809 return *l_serviceNameStr; 810 } 811 else 812 { 813 throw std::runtime_error( 814 "Invalid type received while reading service name."); 815 } 816 } 817 catch (const std::exception& l_ex) 818 { 819 logging::logMessage( 820 "Failed to get service name from connection ID: [" + 821 i_connectionId + "]. error: " + std::string(l_ex.what())); 822 } 823 return std::string{}; 824 } 825 } // namespace dbusUtility 826 } // namespace vpd 827