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