| #pragma once |
| |
| #include "tool_constants.hpp" |
| #include "tool_types.hpp" |
| |
| #include <nlohmann/json.hpp> |
| #include <sdbusplus/bus.hpp> |
| #include <sdbusplus/exception.hpp> |
| |
| #include <fstream> |
| #include <iostream> |
| |
| namespace vpd |
| { |
| namespace utils |
| { |
| /** |
| * @brief An API to read property from Dbus. |
| * |
| * API reads the property value for the specified interface and object path from |
| * the given Dbus service. |
| * |
| * The caller of the API needs to validate the validity and correctness of the |
| * type and value of data returned. The API will just fetch and return the data |
| * without any data validation. |
| * |
| * Note: It will be caller's responsibility to check for empty value returned |
| * and generate appropriate error if required. |
| * |
| * @param[in] i_serviceName - Name of the Dbus service. |
| * @param[in] i_objectPath - Object path under the service. |
| * @param[in] i_interface - Interface under which property exist. |
| * @param[in] i_property - Property whose value is to be read. |
| * |
| * @return - Value read from Dbus. |
| * |
| * @throw std::runtime_error |
| */ |
| inline types::DbusVariantType readDbusProperty( |
| const std::string& i_serviceName, const std::string& i_objectPath, |
| const std::string& i_interface, const std::string& i_property) |
| { |
| types::DbusVariantType l_propertyValue; |
| |
| // Mandatory fields to make a dbus call. |
| if (i_serviceName.empty() || i_objectPath.empty() || i_interface.empty() || |
| i_property.empty()) |
| { |
| // TODO: Enable logging when verbose is enabled. |
| /*std::cout << "One of the parameter to make Dbus read call is empty." |
| << std::endl;*/ |
| throw std::runtime_error("Empty Parameter"); |
| } |
| |
| try |
| { |
| auto l_bus = sdbusplus::bus::new_default(); |
| auto l_method = |
| l_bus.new_method_call(i_serviceName.c_str(), i_objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| l_method.append(i_interface, i_property); |
| |
| auto result = l_bus.call(l_method); |
| result.read(l_propertyValue); |
| } |
| catch (const sdbusplus::exception::SdBusError& l_ex) |
| { |
| // TODO: Enable logging when verbose is enabled. |
| // std::cout << std::string(l_ex.what()) << std::endl; |
| throw std::runtime_error(std::string(l_ex.what())); |
| } |
| return l_propertyValue; |
| } |
| |
| /** |
| * @brief An API to get property map for an interface. |
| * |
| * This API returns a map of property and its value with respect to a particular |
| * interface. |
| * |
| * Note: It will be caller's responsibility to check for empty map returned and |
| * generate appropriate error. |
| * |
| * @param[in] i_service - Service name. |
| * @param[in] i_objectPath - object path. |
| * @param[in] i_interface - Interface, for the properties to be listed. |
| * |
| * @return - A map of property and value of an interface, if success. |
| * if failed, empty map. |
| */ |
| inline types::PropertyMap getPropertyMap( |
| const std::string& i_service, const std::string& i_objectPath, |
| const std::string& i_interface) noexcept |
| { |
| types::PropertyMap l_propertyValueMap; |
| if (i_service.empty() || i_objectPath.empty() || i_interface.empty()) |
| { |
| // TODO: Enable logging when verbose is enabled. |
| // std::cout << "Invalid parameters to get property map" << std::endl; |
| return l_propertyValueMap; |
| } |
| |
| try |
| { |
| auto l_bus = sdbusplus::bus::new_default(); |
| auto l_method = |
| l_bus.new_method_call(i_service.c_str(), i_objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "GetAll"); |
| l_method.append(i_interface); |
| auto l_result = l_bus.call(l_method); |
| l_result.read(l_propertyValueMap); |
| } |
| catch (const sdbusplus::exception::SdBusError& l_ex) |
| { |
| // TODO: Enable logging when verbose is enabled. |
| // std::cerr << "Failed to get property map for service: [" << i_service |
| // << "], object path: [" << i_objectPath |
| // << "] Error : " << l_ex.what() << std::endl; |
| } |
| |
| return l_propertyValueMap; |
| } |
| |
| /** |
| * @brief An API to print json data on stdout. |
| * |
| * @param[in] i_jsonData - JSON object. |
| */ |
| inline void printJson(const nlohmann::json& i_jsonData) |
| { |
| try |
| { |
| std::cout << i_jsonData.dump(constants::INDENTATION) << std::endl; |
| } |
| catch (const nlohmann::json::type_error& l_ex) |
| { |
| throw std::runtime_error( |
| "Failed to dump JSON data, error: " + std::string(l_ex.what())); |
| } |
| } |
| |
| /** |
| * @brief An API to convert binary value into ascii/hex representation. |
| * |
| * If given data contains printable characters, ASCII formated string value of |
| * the input data will be returned. Otherwise if the data has any non-printable |
| * value, returns the hex represented value of the given data in string format. |
| * |
| * @param[in] i_keywordValue - Data in binary format. |
| * |
| * @throw - Throws std::bad_alloc or std::terminate in case of error. |
| * |
| * @return - Returns the converted string value. |
| */ |
| inline std::string getPrintableValue(const types::BinaryVector& i_keywordValue) |
| { |
| bool l_allPrintable = |
| std::all_of(i_keywordValue.begin(), i_keywordValue.end(), |
| [](const auto& l_byte) { return std::isprint(l_byte); }); |
| |
| std::ostringstream l_oss; |
| if (l_allPrintable) |
| { |
| l_oss << std::string(i_keywordValue.begin(), i_keywordValue.end()); |
| } |
| else |
| { |
| l_oss << "0x"; |
| for (const auto& l_byte : i_keywordValue) |
| { |
| l_oss << std::setfill('0') << std::setw(2) << std::hex |
| << static_cast<int>(l_byte); |
| } |
| } |
| |
| return l_oss.str(); |
| } |
| |
| /** |
| * @brief API to read keyword's value from hardware. |
| * |
| * This API reads keyword's value by requesting DBus service(vpd-manager) who |
| * hosts the 'ReadKeyword' method to read keyword's value. |
| * |
| * @param[in] i_eepromPath - EEPROM file path. |
| * @param[in] i_paramsToReadData - Property whose value has to be read. |
| * |
| * @return - Value read from hardware |
| * |
| * @throw std::runtime_error, sdbusplus::exception::SdBusError |
| */ |
| inline types::DbusVariantType readKeywordFromHardware( |
| const std::string& i_eepromPath, |
| const types::ReadVpdParams i_paramsToReadData) |
| { |
| if (i_eepromPath.empty()) |
| { |
| throw std::runtime_error("Empty EEPROM path"); |
| } |
| |
| try |
| { |
| types::DbusVariantType l_propertyValue; |
| |
| auto l_bus = sdbusplus::bus::new_default(); |
| |
| auto l_method = l_bus.new_method_call( |
| constants::vpdManagerService, constants::vpdManagerObjectPath, |
| constants::vpdManagerInfName, "ReadKeyword"); |
| |
| l_method.append(i_eepromPath, i_paramsToReadData); |
| auto l_result = l_bus.call(l_method); |
| |
| l_result.read(l_propertyValue); |
| |
| return l_propertyValue; |
| } |
| catch (const sdbusplus::exception::SdBusError& l_error) |
| { |
| throw; |
| } |
| } |
| |
| /** |
| * @brief API to save keyword's value on file. |
| * |
| * API writes keyword's value on the given file path. If the data is in hex |
| * format, API strips '0x' and saves the value on the given file. |
| * |
| * @param[in] i_filePath - File path. |
| * @param[in] i_keywordValue - Keyword's value. |
| * |
| * @return - true on successfully writing to file, false otherwise. |
| */ |
| inline bool saveToFile(const std::string& i_filePath, |
| const std::string& i_keywordValue) |
| { |
| bool l_returnStatus = false; |
| |
| if (i_keywordValue.empty()) |
| { |
| // ToDo: log only when verbose is enabled |
| std::cerr << "Save to file[ " << i_filePath |
| << "] failed, reason: Empty keyword's value received" |
| << std::endl; |
| return l_returnStatus; |
| } |
| |
| std::string l_keywordValue{i_keywordValue}; |
| if (i_keywordValue.substr(0, 2).compare("0x") == constants::STR_CMP_SUCCESS) |
| { |
| l_keywordValue = i_keywordValue.substr(2); |
| } |
| |
| std::ofstream l_outPutFileStream; |
| l_outPutFileStream.exceptions( |
| std::ifstream::badbit | std::ifstream::failbit); |
| try |
| { |
| l_outPutFileStream.open(i_filePath); |
| |
| if (l_outPutFileStream.is_open()) |
| { |
| l_outPutFileStream.write(l_keywordValue.c_str(), |
| l_keywordValue.size()); |
| l_returnStatus = true; |
| } |
| else |
| { |
| // ToDo: log only when verbose is enabled |
| std::cerr << "Error opening output file " << i_filePath |
| << std::endl; |
| } |
| } |
| catch (const std::ios_base::failure& l_ex) |
| { |
| // ToDo: log only when verbose is enabled |
| std::cerr |
| << "Failed to write to file: " << i_filePath |
| << ", either base folder path doesn't exist or internal error occured, error: " |
| << l_ex.what() << '\n'; |
| } |
| |
| return l_returnStatus; |
| } |
| |
| /** |
| * @brief API to print data in JSON format on console |
| * |
| * @param[in] i_fruPath - FRU path. |
| * @param[in] i_keywordName - Keyword name. |
| * @param[in] i_keywordStrValue - Keyword's value. |
| */ |
| inline void displayOnConsole(const std::string& i_fruPath, |
| const std::string& i_keywordName, |
| const std::string& i_keywordStrValue) |
| { |
| nlohmann::json l_resultInJson = nlohmann::json::object({}); |
| nlohmann::json l_keywordValInJson = nlohmann::json::object({}); |
| |
| l_keywordValInJson.emplace(i_keywordName, i_keywordStrValue); |
| l_resultInJson.emplace(i_fruPath, l_keywordValInJson); |
| |
| printJson(l_resultInJson); |
| } |
| |
| /** |
| * @brief API to write keyword's value. |
| * |
| * This API writes keyword's value by requesting DBus service(vpd-manager) who |
| * hosts the 'UpdateKeyword' method to update keyword's value. |
| * |
| * @param[in] i_vpdPath - EEPROM or object path, where keyword is present. |
| * @param[in] i_paramsToWriteData - Data required to update keyword's value. |
| * |
| * @return - Number of bytes written on success, -1 on failure. |
| * |
| * @throw - std::runtime_error, sdbusplus::exception::SdBusError |
| */ |
| inline int writeKeyword(const std::string& i_vpdPath, |
| const types::WriteVpdParams& i_paramsToWriteData) |
| { |
| if (i_vpdPath.empty()) |
| { |
| throw std::runtime_error("Empty path"); |
| } |
| |
| int l_rc = constants::FAILURE; |
| auto l_bus = sdbusplus::bus::new_default(); |
| |
| auto l_method = l_bus.new_method_call( |
| constants::vpdManagerService, constants::vpdManagerObjectPath, |
| constants::vpdManagerInfName, "UpdateKeyword"); |
| |
| l_method.append(i_vpdPath, i_paramsToWriteData); |
| auto l_result = l_bus.call(l_method); |
| |
| l_result.read(l_rc); |
| return l_rc; |
| } |
| |
| /** |
| * @brief API to write keyword's value on hardware. |
| * |
| * This API writes keyword's value by requesting DBus service(vpd-manager) who |
| * hosts the 'WriteKeywordOnHardware' method to update keyword's value. |
| * |
| * Note: This API updates keyword's value only on the given hardware path, any |
| * backup or redundant EEPROM (if exists) paths won't get updated. |
| * |
| * @param[in] i_eepromPath - EEPROM where keyword is present. |
| * @param[in] i_paramsToWriteData - Data required to update keyword's value. |
| * |
| * @return - Number of bytes written on success, -1 on failure. |
| * |
| * @throw - std::runtime_error, sdbusplus::exception::SdBusError |
| */ |
| inline int writeKeywordOnHardware( |
| const std::string& i_eepromPath, |
| const types::WriteVpdParams& i_paramsToWriteData) |
| { |
| if (i_eepromPath.empty()) |
| { |
| throw std::runtime_error("Empty path"); |
| } |
| |
| int l_rc = constants::FAILURE; |
| auto l_bus = sdbusplus::bus::new_default(); |
| |
| auto l_method = l_bus.new_method_call( |
| constants::vpdManagerService, constants::vpdManagerObjectPath, |
| constants::vpdManagerInfName, "WriteKeywordOnHardware"); |
| |
| l_method.append(i_eepromPath, i_paramsToWriteData); |
| auto l_result = l_bus.call(l_method); |
| |
| l_result.read(l_rc); |
| |
| return l_rc; |
| } |
| |
| /** |
| * @brief API to get data in binary format. |
| * |
| * This API converts given string value into array of binary data. |
| * |
| * @param[in] i_value - Input data. |
| * |
| * @return - Array of binary data on success, throws as exception in case |
| * of any error. |
| * |
| * @throw std::runtime_error, std::out_of_range, std::bad_alloc, |
| * std::invalid_argument |
| */ |
| inline types::BinaryVector convertToBinary(const std::string& i_value) |
| { |
| if (i_value.empty()) |
| { |
| throw std::runtime_error( |
| "Provide a valid hexadecimal input. (Ex. 0x30313233)"); |
| } |
| |
| std::vector<uint8_t> l_binaryValue{}; |
| |
| if (i_value.substr(0, 2).compare("0x") == constants::STR_CMP_SUCCESS) |
| { |
| if (i_value.length() % 2 != 0) |
| { |
| throw std::runtime_error( |
| "Write option accepts 2 digit hex numbers. (Ex. 0x1 " |
| "should be given as 0x01)."); |
| } |
| |
| auto l_value = i_value.substr(2); |
| |
| if (l_value.empty()) |
| { |
| throw std::runtime_error( |
| "Provide a valid hexadecimal input. (Ex. 0x30313233)"); |
| } |
| |
| if (l_value.find_first_not_of("0123456789abcdefABCDEF") != |
| std::string::npos) |
| { |
| throw std::runtime_error("Provide a valid hexadecimal input."); |
| } |
| |
| for (size_t l_pos = 0; l_pos < l_value.length(); l_pos += 2) |
| { |
| uint8_t l_byte = static_cast<uint8_t>( |
| std::stoi(l_value.substr(l_pos, 2), nullptr, 16)); |
| l_binaryValue.push_back(l_byte); |
| } |
| } |
| else |
| { |
| l_binaryValue.assign(i_value.begin(), i_value.end()); |
| } |
| return l_binaryValue; |
| } |
| |
| /** |
| * @brief API to parse respective JSON. |
| * |
| * @param[in] i_pathToJson - Path to JSON. |
| * |
| * @return Parsed JSON, throws exception in case of error. |
| * |
| * @throw std::runtime_error |
| */ |
| inline nlohmann::json getParsedJson(const std::string& i_pathToJson) |
| { |
| if (i_pathToJson.empty()) |
| { |
| throw std::runtime_error("Path to JSON is missing"); |
| } |
| |
| std::error_code l_ec; |
| if (!std::filesystem::exists(i_pathToJson, l_ec)) |
| { |
| std::string l_message{ |
| "file system call failed for file: " + i_pathToJson}; |
| |
| if (l_ec) |
| { |
| l_message += ", error: " + l_ec.message(); |
| } |
| throw std::runtime_error(l_message); |
| } |
| |
| if (std::filesystem::is_empty(i_pathToJson, l_ec)) |
| { |
| throw std::runtime_error("Empty file: " + i_pathToJson); |
| } |
| else if (l_ec) |
| { |
| throw std::runtime_error("is_empty file system call failed for file: " + |
| i_pathToJson + ", error: " + l_ec.message()); |
| } |
| |
| std::ifstream l_jsonFile(i_pathToJson); |
| if (!l_jsonFile) |
| { |
| throw std::runtime_error("Failed to access Json path: " + i_pathToJson); |
| } |
| |
| try |
| { |
| return nlohmann::json::parse(l_jsonFile); |
| } |
| catch (const nlohmann::json::parse_error& l_ex) |
| { |
| throw std::runtime_error("Failed to parse JSON file: " + i_pathToJson); |
| } |
| } |
| |
| /** |
| * @brief API to get list of interfaces under a given object path. |
| * |
| * Given a DBus object path, this API returns a map of service -> implemented |
| * interface(s) under that object path. This API calls DBus method GetObject |
| * hosted by ObjectMapper DBus service. |
| * |
| * @param[in] i_objectPath - DBus object path. |
| * @param[in] i_constrainingInterfaces - An array of result set constraining |
| * interfaces. |
| * |
| * @return On success, returns a map of service -> implemented interface(s), |
| * else returns an empty map. The caller of this |
| * API should check for empty map. |
| */ |
| inline types::MapperGetObject GetServiceInterfacesForObject( |
| const std::string& i_objectPath, |
| const std::vector<std::string>& i_constrainingInterfaces) noexcept |
| { |
| types::MapperGetObject l_serviceInfMap; |
| if (i_objectPath.empty()) |
| { |
| // TODO: log only when verbose is enabled |
| std::cerr << "Object path is empty." << std::endl; |
| return l_serviceInfMap; |
| } |
| |
| try |
| { |
| auto l_bus = sdbusplus::bus::new_default(); |
| auto l_method = l_bus.new_method_call( |
| constants::objectMapperService, constants::objectMapperObjectPath, |
| constants::objectMapperInfName, "GetObject"); |
| |
| l_method.append(i_objectPath, i_constrainingInterfaces); |
| |
| auto l_result = l_bus.call(l_method); |
| l_result.read(l_serviceInfMap); |
| } |
| catch (const sdbusplus::exception::SdBusError& l_ex) |
| { |
| // TODO: log only when verbose is enabled |
| std::cerr << std::string(l_ex.what()) << std::endl; |
| } |
| return l_serviceInfMap; |
| } |
| |
| /** @brief API to get list of sub tree paths for a given object path |
| * |
| * Given a DBus object path, this API returns a list of object paths under that |
| * object path in the DBus tree. This API calls DBus method GetSubTreePaths |
| * hosted by ObjectMapper DBus service. |
| * |
| * @param[in] i_objectPath - DBus object path. |
| * @param[in] i_constrainingInterfaces - An array of result set constraining |
| * interfaces. |
| * @param[in] i_depth - The maximum subtree depth for which results should be |
| * fetched. For unconstrained fetches use a depth of zero. |
| * |
| * @return On success, returns a std::vector<std::string> of object paths in |
| * Phosphor Inventory Manager DBus service's tree, else returns an empty vector. |
| * The caller of this API should check for empty vector. |
| */ |
| inline std::vector<std::string> GetSubTreePaths( |
| const std::string i_objectPath, const int i_depth = 0, |
| const std::vector<std::string>& i_constrainingInterfaces = {}) noexcept |
| { |
| std::vector<std::string> l_objectPaths; |
| |
| try |
| { |
| auto l_bus = sdbusplus::bus::new_default(); |
| auto l_method = l_bus.new_method_call( |
| constants::objectMapperService, constants::objectMapperObjectPath, |
| constants::objectMapperInfName, "GetSubTreePaths"); |
| |
| l_method.append(i_objectPath, i_depth, i_constrainingInterfaces); |
| |
| auto l_result = l_bus.call(l_method); |
| l_result.read(l_objectPaths); |
| } |
| catch (const sdbusplus::exception::SdBusError& l_ex) |
| { |
| // TODO: log only when verbose is enabled |
| std::cerr << std::string(l_ex.what()) << std::endl; |
| } |
| return l_objectPaths; |
| } |
| |
| /** |
| * @brief A class to print data in tabular format |
| * |
| * This class implements methods to print data in a two dimensional tabular |
| * format. All entries in the table must be in string format. |
| * |
| */ |
| class Table |
| { |
| class Column : public types::TableColumnNameSizePair |
| { |
| public: |
| /** |
| * @brief API to get the name of the Column |
| * |
| * @return Name of the Column. |
| */ |
| const std::string& Name() const |
| { |
| return this->first; |
| } |
| |
| /** |
| * @brief API to get the width of the Column |
| * |
| * @return Width of the Column. |
| */ |
| std::size_t Width() const |
| { |
| return this->second; |
| } |
| }; |
| |
| // Current width of the table |
| std::size_t m_currentWidth; |
| |
| // Character to be used as fill character between entries |
| char m_fillCharacter; |
| |
| // Separator character to be used between columns |
| char m_separator; |
| |
| // Array of columns |
| std::vector<Column> m_columns; |
| |
| /** |
| * @brief API to Print Header |
| * |
| * Header line prints the names of the Column headers separated by the |
| * specified separator character and spaced accordingly. |
| * |
| * @throw std::out_of_range, std::length_error, std::bad_alloc |
| */ |
| void PrintHeader() const |
| { |
| for (const auto& l_column : m_columns) |
| { |
| PrintEntry(l_column.Name(), l_column.Width()); |
| } |
| std::cout << m_separator << std::endl; |
| } |
| |
| /** |
| * @brief API to Print Horizontal Line |
| * |
| * A horizontal line is a sequence of '*'s. |
| * |
| * @throw std::out_of_range, std::length_error, std::bad_alloc |
| */ |
| void PrintHorizontalLine() const |
| { |
| std::cout << std::string(m_currentWidth, '*') << std::endl; |
| } |
| |
| /** |
| * @brief API to print an entry in the table |
| * |
| * An entry is a separator character followed by the text to print. |
| * The text is centre-aligned. |
| * |
| * @param[in] i_text - text to print |
| * @param[in] i_columnWidth - width of the column |
| * |
| * @throw std::out_of_range, std::length_error, std::bad_alloc |
| */ |
| void PrintEntry(const std::string& i_text, std::size_t i_columnWidth) const |
| { |
| const std::size_t l_textLength{i_text.length()}; |
| |
| constexpr std::size_t l_minFillChars{3}; |
| const std::size_t l_numFillChars = |
| ((l_textLength >= i_columnWidth ? l_minFillChars |
| : i_columnWidth - l_textLength)) - |
| 1; // -1 for the separator character |
| |
| const unsigned l_oddFill = l_numFillChars % 2; |
| |
| std::cout << m_separator |
| << std::string((l_numFillChars / 2) + l_oddFill, |
| m_fillCharacter) |
| << i_text << std::string(l_numFillChars / 2, m_fillCharacter); |
| } |
| |
| public: |
| /** |
| * @brief Table Constructor |
| * |
| * Parameterized constructor for a Table object |
| * |
| */ |
| constexpr explicit Table(const char i_fillCharacter = ' ', |
| const char i_separator = '|') noexcept : |
| m_currentWidth{0}, m_fillCharacter{i_fillCharacter}, |
| m_separator{i_separator} |
| {} |
| |
| // deleted methods |
| Table(const Table&) = delete; |
| Table operator=(const Table&) = delete; |
| Table(const Table&&) = delete; |
| Table operator=(const Table&&) = delete; |
| |
| ~Table() = default; |
| |
| /** |
| * @brief API to add column to Table |
| * |
| * @param[in] i_name - Name of the column. |
| * |
| * @param[in] i_width - Width to allocate for the column. |
| * |
| * @return On success returns 0, otherwise returns -1. |
| */ |
| int AddColumn(const std::string& i_name, std::size_t i_width) |
| { |
| if (i_width < i_name.length()) |
| return constants::FAILURE; |
| m_columns.emplace_back(types::TableColumnNameSizePair(i_name, i_width)); |
| m_currentWidth += i_width; |
| return constants::SUCCESS; |
| } |
| |
| /** |
| * @brief API to print the Table to console. |
| * |
| * This API prints the table data to console. |
| * |
| * @param[in] i_tableData - The data to be printed. |
| * |
| * @return On success returns 0, otherwise returns -1. |
| * |
| * @throw std::out_of_range, std::length_error, std::bad_alloc |
| */ |
| int Print(const types::TableInputData& i_tableData) const |
| { |
| PrintHorizontalLine(); |
| PrintHeader(); |
| PrintHorizontalLine(); |
| |
| // print the table data |
| for (const auto& l_row : i_tableData) |
| { |
| unsigned l_columnNumber{0}; |
| |
| // number of columns in input data is greater than the number of |
| // columns specified in Table |
| if (l_row.size() > m_columns.size()) |
| { |
| return constants::FAILURE; |
| } |
| |
| for (const auto& l_entry : l_row) |
| { |
| PrintEntry(l_entry, m_columns[l_columnNumber].Width()); |
| |
| ++l_columnNumber; |
| } |
| std::cout << m_separator << std::endl; |
| } |
| PrintHorizontalLine(); |
| return constants::SUCCESS; |
| } |
| }; |
| |
| /** |
| * @brief API to read value from file. |
| * |
| * The API reads the file and returns the read value. |
| * |
| * @param[in] i_filePath - File path. |
| * |
| * @return - Data from file if any in string format, else empty string. |
| * |
| */ |
| inline std::string readValueFromFile(const std::string& i_filePath) |
| { |
| std::string l_valueRead{}; |
| |
| std::error_code l_ec; |
| if (!std::filesystem::exists(i_filePath, l_ec)) |
| { |
| std::string l_message{ |
| "filesystem call exists failed for file [" + i_filePath + "]."}; |
| |
| if (l_ec) |
| { |
| l_message += " Error: " + l_ec.message(); |
| } |
| |
| std::cerr << l_message << std::endl; |
| return l_valueRead; |
| } |
| |
| if (std::filesystem::is_empty(i_filePath, l_ec)) |
| { |
| std::cerr << "File[" << i_filePath << "] is empty." << std::endl; |
| return l_valueRead; |
| } |
| else if (l_ec) |
| { |
| std::cerr << "is_empty file system call failed for file[" << i_filePath |
| << "] , error: " << l_ec.message() << std::endl; |
| |
| return l_valueRead; |
| } |
| |
| std::ifstream l_fileStream; |
| l_fileStream.exceptions(std::ifstream::badbit | std::ifstream::failbit); |
| try |
| { |
| l_fileStream.open(i_filePath, std::ifstream::in); |
| |
| std::getline(l_fileStream, l_valueRead); |
| |
| l_fileStream.close(); |
| return l_valueRead; |
| } |
| catch (const std::ifstream::failure& l_ex) |
| { |
| if (l_fileStream.is_open()) |
| { |
| l_fileStream.close(); |
| } |
| |
| std::cerr << "File read operation failed for path[" << i_filePath |
| << "], error: " << l_ex.what() << std::endl; |
| } |
| |
| return l_valueRead; |
| } |
| |
| /** |
| * @brief API to check if chassis is powered off. |
| * |
| * This API queries Phosphor Chassis State Manager to know whether |
| * chassis is powered off. |
| * |
| * @return true if chassis is powered off, false otherwise. |
| */ |
| inline bool isChassisPowerOff() |
| { |
| try |
| { |
| // ToDo: Handle in case system has multiple chassis |
| auto l_powerState = readDbusProperty( |
| constants::chassisStateManagerService, |
| constants::chassisStateManagerObjectPath, |
| constants::chassisStateManagerInfName, "CurrentPowerState"); |
| |
| if (auto l_curPowerState = std::get_if<std::string>(&l_powerState); |
| l_curPowerState && |
| ("xyz.openbmc_project.State.Chassis.PowerState.Off" == |
| *l_curPowerState)) |
| { |
| return true; |
| } |
| } |
| catch (const std::exception& l_ex) |
| { |
| // Todo: Enale log when verbose is enabled |
| std::cerr << l_ex.what() << std::endl; |
| } |
| return false; |
| } |
| |
| /** |
| * @brief API to check if a D-Bus service is running or not. |
| * |
| * Any failure in calling the method "NameHasOwner" implies that the service |
| * is not in a running state. Hence the API returns false in case of any |
| * exception as well. |
| * |
| * @param[in] i_serviceName - D-Bus service name whose status is to be |
| * checked. |
| * @return bool - True if the service is running, false otherwise. |
| */ |
| inline bool isServiceRunning(const std::string& i_serviceName) noexcept |
| { |
| bool l_retVal = false; |
| |
| try |
| { |
| auto l_bus = sdbusplus::bus::new_default(); |
| auto l_method = l_bus.new_method_call( |
| constants::dbusService, constants::dbusObjectPath, |
| constants::dbusInterface, "NameHasOwner"); |
| l_method.append(i_serviceName); |
| |
| l_bus.call(l_method).read(l_retVal); |
| } |
| catch (const sdbusplus::exception::SdBusError& l_ex) |
| { |
| std::cout << "Call to check service status failed with exception: " + |
| std::string(l_ex.what()) |
| << std::endl; |
| } |
| |
| return l_retVal; |
| } |
| |
| /** |
| * @brief API to call "GetAttribute" method under BIOS Config Manager. |
| * |
| * The API reads the given attribute from BIOS Config Manager and returns a |
| * variant containing current value for that attribute if the value is found. |
| * API returns an empty variant of type BiosAttributeCurrentValue in case of any |
| * error. |
| * |
| * @param[in] i_attributeName - Attribute to be read. |
| * |
| * @return Tuple of PLDM attribute Type, current attribute value and pending |
| * attribute value. |
| */ |
| inline types::BiosAttributeCurrentValue biosGetAttributeMethodCall( |
| const std::string& i_attributeName) noexcept |
| { |
| types::BiosGetAttrRetType l_attributeVal; |
| |
| try |
| { |
| auto l_bus = sdbusplus::bus::new_default(); |
| auto l_method = l_bus.new_method_call( |
| constants::biosConfigMgrService, constants::biosConfigMgrObjPath, |
| constants::biosConfigMgrInterface, "GetAttribute"); |
| l_method.append(i_attributeName); |
| |
| auto l_result = l_bus.call(l_method); |
| l_result.read(std::get<0>(l_attributeVal), std::get<1>(l_attributeVal), |
| std::get<2>(l_attributeVal)); |
| } |
| catch (const sdbusplus::exception::SdBusError& l_ex) |
| { |
| // TODO : enable logging when verbose is implemented |
| std::cerr << "Failed to read BIOS Attribute: " + i_attributeName + |
| " due to error " + std::string(l_ex.what()) |
| << std::endl; |
| } |
| |
| return std::get<1>(l_attributeVal); |
| } |
| |
| /** |
| * @brief Converts string to lower case. |
| * |
| * @param [in,out] io_string - Input string. |
| * |
| * @throw std::terminate, std::bad_alloc |
| */ |
| inline void toLower(std::string& io_string) |
| { |
| std::transform(io_string.begin(), io_string.end(), io_string.begin(), |
| [](const unsigned char& l_char) { |
| return std::tolower(l_char); |
| }); |
| } |
| |
| /** |
| * @brief Converts an integral data value to a vector of bytes. |
| * The LSB of integer is copied to MSB of the vector. |
| * |
| * @param[in] i_integralData - Input integral data. |
| * @param[in] i_numBytesCopy - Number of bytes to copy. |
| * |
| * @return - On success, returns the Binary vector representation of the |
| * integral data, empty binary vector otherwise. |
| * |
| * @throw std::length_error |
| */ |
| template <typename T> |
| requires std::integral<T> |
| inline types::BinaryVector convertIntegralTypeToBytes( |
| const T& i_integralData, size_t i_numBytesCopy = constants::VALUE_1) |
| { |
| types::BinaryVector l_result; |
| constexpr auto l_byteMask{0xFF}; |
| |
| l_result.resize(i_numBytesCopy, constants::VALUE_0); |
| |
| // sanitize number of bytes to copy |
| if (i_numBytesCopy > sizeof(T)) |
| { |
| i_numBytesCopy = sizeof(T); |
| } |
| |
| // LSB of source -> MSB of result |
| for (size_t l_byte = 0; l_byte < i_numBytesCopy; ++l_byte) |
| { |
| l_result[l_result.size() - (l_byte + constants::VALUE_1)] = |
| (i_integralData >> (l_byte * constants::VALUE_8)) & l_byteMask; |
| } |
| return l_result; |
| } |
| |
| } // namespace utils |
| } // namespace vpd |