| #include "pdr_file.hpp" |
| |
| #include <libpldm/entity.h> |
| |
| #include <phosphor-logging/lg2.hpp> |
| |
| PHOSPHOR_LOG2_USING; |
| |
| namespace pldm |
| { |
| namespace responder |
| { |
| namespace pdr_file |
| { |
| |
| using Json = nlohmann::json; |
| |
| void generateFileDescriptorPDR( |
| const Json& json, std::map<uint16_t, FileInfo>& fileIdentifierToFileInfo, |
| std::map<uint32_t, FileInfo>& recordHandleToFileInfo, |
| pdr_utils::RepoInterface& repo) |
| { |
| static const std::vector<Json> emptyList{}; |
| auto entries = json.value("entries", emptyList); |
| for (const auto& e : entries) |
| { |
| auto entityTypeIt = e.find("EntityType"); |
| if (entityTypeIt == e.end() || !entityTypeIt->is_number()) |
| { |
| error("EntityType is missing or it is not a number."); |
| continue; |
| } |
| |
| uint16_t entityType = static_cast<uint16_t>(*entityTypeIt); |
| if ((entityType != PLDM_ENTITY_DEVICE_FILE) && |
| (entityType != PLDM_ENTITY_DEVICE_FILE_DIRECTORY)) |
| { |
| error( |
| "Invalid EntityType '{ENTITY_TYPE}' for file descriptor PDR. Expected 9 or 10.", |
| "ENTITY_TYPE", entityType); |
| continue; |
| } |
| |
| auto pathIt = e.find("Path"); |
| if (pathIt == e.end() || !pathIt->is_string()) |
| { |
| error("'Path' is missing or it is not a string."); |
| continue; |
| } |
| |
| uint16_t container_id = e.value("container", 0); |
| |
| auto files = e.value("Files", emptyList); |
| for (const auto& file : files) |
| { |
| auto fileIdIt = file.find("FileIdentifier"); |
| if (fileIdIt == file.end() || !fileIdIt->is_number()) |
| { |
| error("FileIdentifier is missing or it is not a number."); |
| continue; |
| } |
| |
| auto fileNameIt = file.find("FileName"); |
| if (fileNameIt == file.end() || !fileNameIt->is_string()) |
| { |
| error("FileName is missing or it is not a string."); |
| continue; |
| } |
| |
| auto fileSizeIt = file.find("FileSize"); |
| if (fileSizeIt == file.end() || !fileSizeIt->is_number()) |
| { |
| error("FileSize is missing or it is not a string."); |
| continue; |
| } |
| |
| const std::string& fileName = fileNameIt.value(); |
| int fileNameLengthWithNull = fileName.length() + 1; |
| |
| // Calculate the total length of the PDR including the common PDR |
| // header size. For now this skips the |
| // OemFileClassificationNameLength and OemFileClassificationName |
| // since they are not included. |
| size_t pdrSize = PLDM_PDR_FILE_DESCRIPTOR_PDR_MIN_LENGTH + |
| fileNameLengthWithNull; |
| pldm_platform_file_descriptor_pdr pdr{}; |
| |
| // This will be assigned automatically by PDR repository. |
| pdr.hdr.record_handle = 0; |
| pdr.hdr.version = 1; |
| pdr.hdr.type = PLDM_FILE_DESCRIPTOR_PDR; |
| pdr.hdr.record_change_num = 0; |
| pdr.hdr.length = pdrSize - sizeof(pldm_pdr_hdr); |
| |
| pdr.terminus_handle = TERMINUS_HANDLE; |
| pdr.file_identifier = *fileIdIt; |
| pdr.container.entity_type = entityType; |
| pdr.container.entity_instance_num = file.value("InstanceNumber", 0); |
| pdr.container.entity_container_id = container_id; |
| pdr.superior_directory_file_identifier = |
| file.value("SuperiorDirectoryFileIdentifier", 0); |
| pdr.file_classification = file.value("FileClassification", 0); |
| pdr.oem_file_classification = 0; |
| pdr.file_capabilities.value = file.value("FileCapabilities", 0); |
| pdr.file_maximum_size = fileSizeIt.value(); |
| pdr.file_maximum_file_descriptor_count = |
| file.value("MaxFileDescriptors", 0); |
| pdr.file_name.ptr = |
| reinterpret_cast<const uint8_t*>(fileName.c_str()); |
| pdr.file_name.length = fileNameLengthWithNull; |
| pdr.oem_file_classification_name.ptr = nullptr; |
| pdr.oem_file_classification_name.length = 0; |
| |
| std::vector<uint8_t> entry{}; |
| entry.resize(pdrSize); |
| |
| size_t pdrSizeCopy = pdrSize; |
| int ret = encode_pldm_platform_file_descriptor_pdr( |
| &pdr, entry.data(), &pdrSizeCopy); |
| if (ret != 0) |
| { |
| error("Failed to encode file descriptor PDR for '{FILE_NAME}'", |
| "FILE_NAME", fileName); |
| continue; |
| } |
| |
| FileInfo fileInfo{}; |
| |
| // Try opening the file here. If the open fail, we will not save the |
| // PDR. If we do open the file later on, PDR information and the |
| // actual file might not be in sync. |
| fileInfo.filePath = pathIt->get<std::string>() + "/" + fileName; |
| FILE* fp = fopen(fileInfo.filePath.c_str(), "rb"); |
| if (fp == nullptr) |
| { |
| error("Failed to open file '{FILE_PATH}'", "FILE_PATH", |
| fileInfo.filePath); |
| continue; |
| } |
| |
| // This file pointer will be kept open through out the lifetime of |
| // the program |
| // TODO: If the file changes during runtime, we need to load it |
| // again. At that time we will close this and open a file pointer to |
| // the new file. |
| fileInfo.fp = fp; |
| fileInfo.fileIdentifier = *fileIdIt; |
| fileInfo.fileSize = fileSizeIt.value(); |
| |
| pdr_utils::PdrEntry pdrEntry{}; |
| pdrEntry.data = entry.data(); |
| pdrEntry.size = pdrSize; |
| pdr_utils::RecordHandle recordHandle; |
| |
| try |
| { |
| recordHandle = repo.addRecord(pdrEntry); |
| } |
| catch (const std::runtime_error& e) |
| { |
| error("Error adding record for file '{FILE_PATH}'", "FILE_PATH", |
| fileInfo.filePath); |
| continue; |
| } |
| |
| fileInfo.recordHandle = static_cast<uint32_t>(recordHandle); |
| |
| fileIdentifierToFileInfo.try_emplace(*fileIdIt, fileInfo); |
| recordHandleToFileInfo.try_emplace( |
| static_cast<uint32_t>(recordHandle), fileInfo); |
| } |
| } |
| } |
| |
| } // namespace pdr_file |
| } // namespace responder |
| } // namespace pldm |