1 #include "utils.hpp" 2 3 #include <libpldm/pdr.h> 4 #include <libpldm/pldm_types.h> 5 6 #include <phosphor-logging/lg2.hpp> 7 #include <xyz/openbmc_project/Common/error.hpp> 8 9 #include <algorithm> 10 #include <array> 11 #include <cctype> 12 #include <ctime> 13 #include <fstream> 14 #include <iostream> 15 #include <map> 16 #include <stdexcept> 17 #include <string> 18 #include <vector> 19 20 PHOSPHOR_LOG2_USING; 21 22 namespace pldm 23 { 24 namespace utils 25 { 26 constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper"; 27 constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper"; 28 constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper"; 29 30 Entities getParentEntites(const EntityAssociations& entityAssoc) 31 { 32 Entities parents{}; 33 for (const auto& et : entityAssoc) 34 { 35 parents.push_back(et[0]); 36 } 37 38 bool found = false; 39 for (auto it = parents.begin(); it != parents.end(); 40 it = found ? parents.erase(it) : std::next(it)) 41 { 42 uint16_t parent_contained_id = 43 pldm_entity_node_get_remote_container_id(*it); 44 found = false; 45 for (const auto& evs : entityAssoc) 46 { 47 for (size_t i = 1; i < evs.size() && !found; i++) 48 { 49 uint16_t node_contained_id = 50 pldm_entity_node_get_remote_container_id(evs[i]); 51 52 pldm_entity parent_entity = pldm_entity_extract(*it); 53 pldm_entity node_entity = pldm_entity_extract(evs[i]); 54 55 if (node_entity.entity_type == parent_entity.entity_type && 56 node_entity.entity_instance_num == 57 parent_entity.entity_instance_num && 58 node_contained_id == parent_contained_id) 59 { 60 found = true; 61 } 62 } 63 if (found) 64 { 65 break; 66 } 67 } 68 } 69 70 return parents; 71 } 72 73 void addObjectPathEntityAssociations(const EntityAssociations& entityAssoc, 74 pldm_entity_node* entity, 75 const fs::path& path, 76 ObjectPathMaps& objPathMap) 77 { 78 if (entity == nullptr) 79 { 80 return; 81 } 82 83 bool found = false; 84 pldm_entity node_entity = pldm_entity_extract(entity); 85 if (!entityMaps.contains(node_entity.entity_type)) 86 { 87 lg2::info( 88 "{ENTITY_TYPE} Entity fetched from remote PLDM terminal does not exist.", 89 "ENTITY_TYPE", (int)node_entity.entity_type); 90 return; 91 } 92 93 std::string entityName = entityMaps.at(node_entity.entity_type); 94 for (const auto& ev : entityAssoc) 95 { 96 pldm_entity ev_entity = pldm_entity_extract(ev[0]); 97 if (ev_entity.entity_instance_num == node_entity.entity_instance_num && 98 ev_entity.entity_type == node_entity.entity_type) 99 { 100 uint16_t node_contained_id = 101 pldm_entity_node_get_remote_container_id(ev[0]); 102 uint16_t entity_contained_id = 103 pldm_entity_node_get_remote_container_id(entity); 104 105 if (node_contained_id != entity_contained_id) 106 { 107 continue; 108 } 109 110 fs::path p = path / fs::path{entityName + 111 std::to_string( 112 node_entity.entity_instance_num)}; 113 std::string entity_path = p.string(); 114 // If the entity obtained from the remote PLDM terminal is not in 115 // the MAP, or there is no auxiliary name PDR, add it directly. 116 // Otherwise, check whether the DBus service of entity_path exists, 117 // and overwrite the entity if it does not exist. 118 if (!objPathMap.contains(entity_path)) 119 { 120 objPathMap[entity_path] = entity; 121 } 122 else 123 { 124 try 125 { 126 pldm::utils::DBusHandler().getService(entity_path.c_str(), 127 nullptr); 128 } 129 catch (const std::exception& e) 130 { 131 objPathMap[entity_path] = entity; 132 } 133 } 134 135 for (size_t i = 1; i < ev.size(); i++) 136 { 137 addObjectPathEntityAssociations(entityAssoc, ev[i], p, 138 objPathMap); 139 } 140 found = true; 141 } 142 } 143 144 if (!found) 145 { 146 std::string dbusPath = 147 path / fs::path{entityName + 148 std::to_string(node_entity.entity_instance_num)}; 149 150 try 151 { 152 pldm::utils::DBusHandler().getService(dbusPath.c_str(), nullptr); 153 } 154 catch (const std::exception& e) 155 { 156 objPathMap[dbusPath] = entity; 157 } 158 } 159 } 160 161 void updateEntityAssociation(const EntityAssociations& entityAssoc, 162 pldm_entity_association_tree* entityTree, 163 ObjectPathMaps& objPathMap) 164 { 165 std::vector<pldm_entity_node*> parentsEntity = 166 getParentEntites(entityAssoc); 167 for (const auto& entity : parentsEntity) 168 { 169 fs::path path{"/xyz/openbmc_project/inventory"}; 170 std::deque<std::string> paths{}; 171 pldm_entity node_entity = pldm_entity_extract(entity); 172 auto node = pldm_entity_association_tree_find_with_locality( 173 entityTree, &node_entity, false); 174 if (!node) 175 { 176 continue; 177 } 178 179 bool found = true; 180 while (node) 181 { 182 if (!pldm_entity_is_exist_parent(node)) 183 { 184 break; 185 } 186 187 pldm_entity parent = pldm_entity_get_parent(node); 188 try 189 { 190 paths.push_back(entityMaps.at(parent.entity_type) + 191 std::to_string(parent.entity_instance_num)); 192 } 193 catch (const std::exception& e) 194 { 195 lg2::error( 196 "Parent entity not found in the entityMaps, type: {ENTITY_TYPE}, num: {NUM}, e: {ERROR}", 197 "ENTITY_TYPE", (int)parent.entity_type, "NUM", 198 (int)parent.entity_instance_num, "ERROR", e); 199 found = false; 200 break; 201 } 202 203 node = pldm_entity_association_tree_find_with_locality( 204 entityTree, &parent, false); 205 } 206 207 if (!found) 208 { 209 continue; 210 } 211 212 while (!paths.empty()) 213 { 214 path = path / fs::path{paths.back()}; 215 paths.pop_back(); 216 } 217 218 addObjectPathEntityAssociations(entityAssoc, entity, path, objPathMap); 219 } 220 } 221 222 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t /*tid*/, 223 uint16_t entityID, 224 uint16_t stateSetId, 225 const pldm_pdr* repo) 226 { 227 uint8_t* outData = nullptr; 228 uint32_t size{}; 229 const pldm_pdr_record* record{}; 230 std::vector<std::vector<uint8_t>> pdrs; 231 try 232 { 233 do 234 { 235 record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_EFFECTER_PDR, 236 record, &outData, &size); 237 if (record) 238 { 239 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(outData); 240 auto compositeEffecterCount = pdr->composite_effecter_count; 241 auto possible_states_start = pdr->possible_states; 242 243 for (auto effecters = 0x00; effecters < compositeEffecterCount; 244 effecters++) 245 { 246 auto possibleStates = 247 reinterpret_cast<state_effecter_possible_states*>( 248 possible_states_start); 249 auto setId = possibleStates->state_set_id; 250 auto possibleStateSize = 251 possibleStates->possible_states_size; 252 253 if (pdr->entity_type == entityID && setId == stateSetId) 254 { 255 std::vector<uint8_t> effecter_pdr(&outData[0], 256 &outData[size]); 257 pdrs.emplace_back(std::move(effecter_pdr)); 258 break; 259 } 260 possible_states_start += possibleStateSize + sizeof(setId) + 261 sizeof(possibleStateSize); 262 } 263 } 264 265 } while (record); 266 } 267 catch (const std::exception& e) 268 { 269 error(" Failed to obtain a record. ERROR = {ERR_EXCEP}", "ERR_EXCEP", 270 e.what()); 271 } 272 273 return pdrs; 274 } 275 276 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t /*tid*/, 277 uint16_t entityID, 278 uint16_t stateSetId, 279 const pldm_pdr* repo) 280 { 281 uint8_t* outData = nullptr; 282 uint32_t size{}; 283 const pldm_pdr_record* record{}; 284 std::vector<std::vector<uint8_t>> pdrs; 285 try 286 { 287 do 288 { 289 record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_SENSOR_PDR, 290 record, &outData, &size); 291 if (record) 292 { 293 auto pdr = reinterpret_cast<pldm_state_sensor_pdr*>(outData); 294 auto compositeSensorCount = pdr->composite_sensor_count; 295 auto possible_states_start = pdr->possible_states; 296 297 for (auto sensors = 0x00; sensors < compositeSensorCount; 298 sensors++) 299 { 300 auto possibleStates = 301 reinterpret_cast<state_sensor_possible_states*>( 302 possible_states_start); 303 auto setId = possibleStates->state_set_id; 304 auto possibleStateSize = 305 possibleStates->possible_states_size; 306 307 if (pdr->entity_type == entityID && setId == stateSetId) 308 { 309 std::vector<uint8_t> sensor_pdr(&outData[0], 310 &outData[size]); 311 pdrs.emplace_back(std::move(sensor_pdr)); 312 break; 313 } 314 possible_states_start += possibleStateSize + sizeof(setId) + 315 sizeof(possibleStateSize); 316 } 317 } 318 319 } while (record); 320 } 321 catch (const std::exception& e) 322 { 323 error(" Failed to obtain a record. ERROR = {ERR_EXCEP}", "ERR_EXCEP", 324 e.what()); 325 } 326 327 return pdrs; 328 } 329 330 uint8_t readHostEID() 331 { 332 uint8_t eid{}; 333 std::ifstream eidFile{HOST_EID_PATH}; 334 if (!eidFile.good()) 335 { 336 error("Could not open host EID file: {HOST_PATH}", "HOST_PATH", 337 static_cast<std::string>(HOST_EID_PATH)); 338 } 339 else 340 { 341 std::string eidStr; 342 eidFile >> eidStr; 343 if (!eidStr.empty()) 344 { 345 eid = atoi(eidStr.c_str()); 346 } 347 else 348 { 349 error("Host EID file was empty"); 350 } 351 } 352 353 return eid; 354 } 355 356 uint8_t getNumPadBytes(uint32_t data) 357 { 358 uint8_t pad; 359 pad = ((data % 4) ? (4 - data % 4) : 0); 360 return pad; 361 } // end getNumPadBytes 362 363 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day, 364 uint8_t* hour, uint8_t* min, uint8_t* sec) 365 { 366 constexpr uint64_t max_data = 29991231115959; 367 constexpr uint64_t min_data = 19700101000000; 368 if (data < min_data || data > max_data) 369 { 370 return false; 371 } 372 373 *year = data / 10000000000; 374 data = data % 10000000000; 375 *month = data / 100000000; 376 data = data % 100000000; 377 *day = data / 1000000; 378 data = data % 1000000; 379 *hour = data / 10000; 380 data = data % 10000; 381 *min = data / 100; 382 *sec = data % 100; 383 384 return true; 385 } 386 387 std::optional<std::vector<set_effecter_state_field>> 388 parseEffecterData(const std::vector<uint8_t>& effecterData, 389 uint8_t effecterCount) 390 { 391 std::vector<set_effecter_state_field> stateField; 392 393 if (effecterData.size() != effecterCount * 2) 394 { 395 return std::nullopt; 396 } 397 398 for (uint8_t i = 0; i < effecterCount; ++i) 399 { 400 uint8_t set_request = effecterData[i * 2] == PLDM_REQUEST_SET 401 ? PLDM_REQUEST_SET 402 : PLDM_NO_CHANGE; 403 set_effecter_state_field filed{set_request, effecterData[i * 2 + 1]}; 404 stateField.emplace_back(std::move(filed)); 405 } 406 407 return std::make_optional(std::move(stateField)); 408 } 409 410 std::string DBusHandler::getService(const char* path, 411 const char* interface) const 412 { 413 using DbusInterfaceList = std::vector<std::string>; 414 std::map<std::string, std::vector<std::string>> mapperResponse; 415 auto& bus = DBusHandler::getBus(); 416 417 auto mapper = bus.new_method_call(mapperBusName, mapperPath, 418 mapperInterface, "GetObject"); 419 420 if (interface) 421 { 422 mapper.append(path, DbusInterfaceList({interface})); 423 } 424 else 425 { 426 mapper.append(path, DbusInterfaceList({})); 427 } 428 429 auto mapperResponseMsg = bus.call(mapper, dbusTimeout); 430 mapperResponseMsg.read(mapperResponse); 431 return mapperResponse.begin()->first; 432 } 433 434 GetSubTreeResponse 435 DBusHandler::getSubtree(const std::string& searchPath, int depth, 436 const std::vector<std::string>& ifaceList) const 437 { 438 auto& bus = pldm::utils::DBusHandler::getBus(); 439 auto method = bus.new_method_call(mapperBusName, mapperPath, 440 mapperInterface, "GetSubTree"); 441 method.append(searchPath, depth, ifaceList); 442 auto reply = bus.call(method, dbusTimeout); 443 GetSubTreeResponse response; 444 reply.read(response); 445 return response; 446 } 447 448 void reportError(const char* errorMsg) 449 { 450 static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; 451 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create"; 452 453 auto& bus = pldm::utils::DBusHandler::getBus(); 454 455 try 456 { 457 auto service = DBusHandler().getService(logObjPath, logInterface); 458 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 459 auto severity = 460 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 461 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 462 Error); 463 auto method = bus.new_method_call(service.c_str(), logObjPath, 464 logInterface, "Create"); 465 std::map<std::string, std::string> addlData{}; 466 method.append(errorMsg, severity, addlData); 467 bus.call_noreply(method, dbusTimeout); 468 } 469 catch (const std::exception& e) 470 { 471 error( 472 "failed to make a d-bus call to create error log, ERROR={ERR_EXCEP}", 473 "ERR_EXCEP", e.what()); 474 } 475 } 476 477 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap, 478 const PropertyValue& value) const 479 { 480 auto setDbusValue = [&dBusMap, this](const auto& variant) { 481 auto& bus = getBus(); 482 auto service = getService(dBusMap.objectPath.c_str(), 483 dBusMap.interface.c_str()); 484 auto method = bus.new_method_call( 485 service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set"); 486 method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(), 487 variant); 488 bus.call_noreply(method, dbusTimeout); 489 }; 490 491 if (dBusMap.propertyType == "uint8_t") 492 { 493 std::variant<uint8_t> v = std::get<uint8_t>(value); 494 setDbusValue(v); 495 } 496 else if (dBusMap.propertyType == "bool") 497 { 498 std::variant<bool> v = std::get<bool>(value); 499 setDbusValue(v); 500 } 501 else if (dBusMap.propertyType == "int16_t") 502 { 503 std::variant<int16_t> v = std::get<int16_t>(value); 504 setDbusValue(v); 505 } 506 else if (dBusMap.propertyType == "uint16_t") 507 { 508 std::variant<uint16_t> v = std::get<uint16_t>(value); 509 setDbusValue(v); 510 } 511 else if (dBusMap.propertyType == "int32_t") 512 { 513 std::variant<int32_t> v = std::get<int32_t>(value); 514 setDbusValue(v); 515 } 516 else if (dBusMap.propertyType == "uint32_t") 517 { 518 std::variant<uint32_t> v = std::get<uint32_t>(value); 519 setDbusValue(v); 520 } 521 else if (dBusMap.propertyType == "int64_t") 522 { 523 std::variant<int64_t> v = std::get<int64_t>(value); 524 setDbusValue(v); 525 } 526 else if (dBusMap.propertyType == "uint64_t") 527 { 528 std::variant<uint64_t> v = std::get<uint64_t>(value); 529 setDbusValue(v); 530 } 531 else if (dBusMap.propertyType == "double") 532 { 533 std::variant<double> v = std::get<double>(value); 534 setDbusValue(v); 535 } 536 else if (dBusMap.propertyType == "string") 537 { 538 std::variant<std::string> v = std::get<std::string>(value); 539 setDbusValue(v); 540 } 541 else 542 { 543 throw std::invalid_argument("UnSpported Dbus Type"); 544 } 545 } 546 547 PropertyValue DBusHandler::getDbusPropertyVariant( 548 const char* objPath, const char* dbusProp, const char* dbusInterface) const 549 { 550 auto& bus = DBusHandler::getBus(); 551 auto service = getService(objPath, dbusInterface); 552 auto method = bus.new_method_call(service.c_str(), objPath, dbusProperties, 553 "Get"); 554 method.append(dbusInterface, dbusProp); 555 PropertyValue value{}; 556 auto reply = bus.call(method, dbusTimeout); 557 reply.read(value); 558 return value; 559 } 560 561 PropertyValue jsonEntryToDbusVal(std::string_view type, 562 const nlohmann::json& value) 563 { 564 PropertyValue propValue{}; 565 if (type == "uint8_t") 566 { 567 propValue = static_cast<uint8_t>(value); 568 } 569 else if (type == "uint16_t") 570 { 571 propValue = static_cast<uint16_t>(value); 572 } 573 else if (type == "uint32_t") 574 { 575 propValue = static_cast<uint32_t>(value); 576 } 577 else if (type == "uint64_t") 578 { 579 propValue = static_cast<uint64_t>(value); 580 } 581 else if (type == "int16_t") 582 { 583 propValue = static_cast<int16_t>(value); 584 } 585 else if (type == "int32_t") 586 { 587 propValue = static_cast<int32_t>(value); 588 } 589 else if (type == "int64_t") 590 { 591 propValue = static_cast<int64_t>(value); 592 } 593 else if (type == "bool") 594 { 595 propValue = static_cast<bool>(value); 596 } 597 else if (type == "double") 598 { 599 propValue = static_cast<double>(value); 600 } 601 else if (type == "string") 602 { 603 propValue = static_cast<std::string>(value); 604 } 605 else 606 { 607 error("Unknown D-Bus property type, TYPE={OTHER_TYPE}", "OTHER_TYPE", 608 type); 609 } 610 611 return propValue; 612 } 613 614 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 615 uint16_t entityInstance, uint16_t containerId, 616 uint16_t stateSetId, bool localOrRemote) 617 { 618 uint8_t* pdrData = nullptr; 619 uint32_t pdrSize{}; 620 const pldm_pdr_record* record{}; 621 do 622 { 623 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 624 record, &pdrData, &pdrSize); 625 if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record))) 626 { 627 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 628 auto compositeEffecterCount = pdr->composite_effecter_count; 629 auto possible_states_start = pdr->possible_states; 630 631 for (auto effecters = 0x00; effecters < compositeEffecterCount; 632 effecters++) 633 { 634 auto possibleStates = 635 reinterpret_cast<state_effecter_possible_states*>( 636 possible_states_start); 637 auto setId = possibleStates->state_set_id; 638 auto possibleStateSize = possibleStates->possible_states_size; 639 640 if (entityType == pdr->entity_type && 641 entityInstance == pdr->entity_instance && 642 containerId == pdr->container_id && stateSetId == setId) 643 { 644 return pdr->effecter_id; 645 } 646 possible_states_start += possibleStateSize + sizeof(setId) + 647 sizeof(possibleStateSize); 648 } 649 } 650 } while (record); 651 652 return PLDM_INVALID_EFFECTER_ID; 653 } 654 655 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 656 uint8_t sensorOffset, uint8_t eventState, 657 uint8_t previousEventState) 658 { 659 try 660 { 661 auto& bus = DBusHandler::getBus(); 662 auto msg = bus.new_signal("/xyz/openbmc_project/pldm", 663 "xyz.openbmc_project.PLDM.Event", 664 "StateSensorEvent"); 665 msg.append(tid, sensorId, sensorOffset, eventState, previousEventState); 666 667 msg.signal_send(); 668 } 669 catch (const std::exception& e) 670 { 671 error("Error emitting pldm event signal:ERROR={ERR_EXCEP}", "ERR_EXCEP", 672 e.what()); 673 return PLDM_ERROR; 674 } 675 676 return PLDM_SUCCESS; 677 } 678 679 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid, 680 uint16_t entityType, uint16_t entityInstance, 681 uint16_t containerId, uint16_t stateSetId) 682 { 683 auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo); 684 for (auto pdr : pdrs) 685 { 686 auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data()); 687 auto compositeSensorCount = sensorPdr->composite_sensor_count; 688 auto possible_states_start = sensorPdr->possible_states; 689 690 for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++) 691 { 692 auto possibleStates = 693 reinterpret_cast<state_sensor_possible_states*>( 694 possible_states_start); 695 auto setId = possibleStates->state_set_id; 696 auto possibleStateSize = possibleStates->possible_states_size; 697 if (entityType == sensorPdr->entity_type && 698 entityInstance == sensorPdr->entity_instance && 699 stateSetId == setId && containerId == sensorPdr->container_id) 700 { 701 return sensorPdr->sensor_id; 702 } 703 possible_states_start += possibleStateSize + sizeof(setId) + 704 sizeof(possibleStateSize); 705 } 706 } 707 return PLDM_INVALID_EFFECTER_ID; 708 } 709 710 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer) 711 { 712 if (!buffer.empty()) 713 { 714 if (isTx) 715 { 716 std::cout << "Tx: "; 717 } 718 else 719 { 720 std::cout << "Rx: "; 721 } 722 std::ostringstream tempStream; 723 for (int byte : buffer) 724 { 725 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 726 << " "; 727 } 728 std::cout << tempStream.str() << std::endl; 729 } 730 } 731 732 std::string toString(const struct variable_field& var) 733 { 734 if (var.ptr == nullptr || !var.length) 735 { 736 return ""; 737 } 738 739 std::string str(reinterpret_cast<const char*>(var.ptr), var.length); 740 std::replace_if( 741 str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' '); 742 return str; 743 } 744 745 std::vector<std::string> split(std::string_view srcStr, std::string_view delim, 746 std::string_view trimStr) 747 { 748 std::vector<std::string> out; 749 size_t start; 750 size_t end = 0; 751 752 while ((start = srcStr.find_first_not_of(delim, end)) != std::string::npos) 753 { 754 end = srcStr.find(delim, start); 755 std::string_view dstStr = srcStr.substr(start, end - start); 756 if (!trimStr.empty()) 757 { 758 dstStr.remove_prefix(dstStr.find_first_not_of(trimStr)); 759 dstStr.remove_suffix(dstStr.size() - 1 - 760 dstStr.find_last_not_of(trimStr)); 761 } 762 763 if (!dstStr.empty()) 764 { 765 out.push_back(std::string(dstStr)); 766 } 767 } 768 769 return out; 770 } 771 772 std::string getCurrentSystemTime() 773 { 774 using namespace std::chrono; 775 const time_point<system_clock> tp = system_clock::now(); 776 std::time_t tt = system_clock::to_time_t(tp); 777 auto ms = duration_cast<microseconds>(tp.time_since_epoch()) - 778 duration_cast<seconds>(tp.time_since_epoch()); 779 780 std::stringstream ss; 781 ss << std::put_time(std::localtime(&tt), "%F %Z %T.") 782 << std::to_string(ms.count()); 783 return ss.str(); 784 } 785 786 bool checkForFruPresence(const std::string& objPath) 787 { 788 bool isPresent = false; 789 static constexpr auto presentInterface = 790 "xyz.openbmc_project.Inventory.Item"; 791 static constexpr auto presentProperty = "Present"; 792 try 793 { 794 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( 795 objPath.c_str(), presentProperty, presentInterface); 796 isPresent = std::get<bool>(propVal); 797 } 798 catch (const sdbusplus::exception::SdBusError& e) 799 { 800 error( 801 "Failed to check for FRU presence for {OBJ_PATH} ERROR = {ERR_EXCEP}", 802 "OBJ_PATH", objPath.c_str(), "ERR_EXCEP", e.what()); 803 } 804 return isPresent; 805 } 806 807 bool checkIfLogicalBitSet(const uint16_t& containerId) 808 { 809 return !(containerId & 0x8000); 810 } 811 812 } // namespace utils 813 } // namespace pldm 814