Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vpd-tool: enable verbose flag #504

Draft
wants to merge 2 commits into
base: P11_Dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions vpd-tool/include/tool_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ namespace constants
{
static constexpr auto KEYWORD_SIZE = 2;
static constexpr auto RECORD_SIZE = 4;
static constexpr auto INDENTATION = 4;

constexpr auto inventoryManagerService =
"xyz.openbmc_project.Inventory.Manager";
constexpr auto baseInventoryPath = "/xyz/openbmc_project/inventory";
constexpr auto ipzVpdInfPrefix = "com.ibm.ipzvpd.";
} // namespace constants
} // namespace vpd
44 changes: 44 additions & 0 deletions vpd-tool/include/tool_types.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <sdbusplus/message/types.hpp>

#include <cstdint>
#include <tuple>
#include <variant>
#include <vector>

namespace vpd
{
namespace types
{
using BinaryVector = std::vector<uint8_t>;

// This covers mostly all the data type supported over DBus for a property.
// clang-format off
using DbusVariantType = std::variant<
std::vector<std::tuple<std::string, std::string, std::string>>,
std::vector<std::string>,
std::vector<double>,
std::string,
int64_t,
uint64_t,
double,
int32_t,
uint32_t,
int16_t,
uint16_t,
uint8_t,
bool,
BinaryVector,
std::vector<uint32_t>,
std::vector<uint16_t>,
sdbusplus::message::object_path,
std::tuple<uint64_t, std::vector<std::tuple<std::string, std::string, double, uint64_t>>>,
std::vector<std::tuple<std::string, std::string>>,
std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>,
std::vector<std::tuple<uint32_t, size_t>>,
std::vector<std::tuple<sdbusplus::message::object_path, std::string,
std::string, std::string>>
>;
} // namespace types
} // namespace vpd
133 changes: 133 additions & 0 deletions vpd-tool/include/tool_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#pragma once

#include "tool_types.hpp"

#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/exception.hpp>

#include <iostream>

extern bool VerboseMode;

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, if success.
* If failed, empty variant.
*/
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())
{
if (VerboseMode)
{
std::cout << "One of the parameter to make Dbus read call is empty."
<< std::endl;
}
return l_propertyValue;
}

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)
{
if (VerboseMode)
{
std::cout << std::string(l_ex.what()) << std::endl;
}
}
return l_propertyValue;
}

/**
* @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 hex value to string.
*
* 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 hex.
*
* @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();
}
} // namespace utils
} // namespace vpd
6 changes: 3 additions & 3 deletions vpd-tool/include/vpd_tool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ class VpdTool
* If the provided i_onHardware option is true, read keyword's value from
* the hardware. Otherwise read keyword's value from DBus.
*
* @param[in] i_fruPath - DBus object path or EEPROM path.
* @param[in] i_vpdPath - DBus object path or EEPROM path.
* @param[in] i_recordName - Record name.
* @param[in] i_keywordName - Keyword name.
* @param[in] i_onHardware - True if i_fruPath is EEPROM path, false
* @param[in] i_onHardware - True if i_vpdPath is EEPROM path, false
* otherwise.
* @param[in] i_fileToSave - File path to save keyword's value, if not given
* result will redirect to a console.
*
* @return On success return 0, otherwise return -1.
*/
int readKeyword(const std::string& i_fruPath,
int readKeyword(const std::string& i_vpdPath,
const std::string& i_recordName,
const std::string& i_keywordName, const bool i_onHardware,
const std::string& i_fileToSave = {});
Expand Down
3 changes: 2 additions & 1 deletion vpd-tool/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ else
CLI11_dep = dependency('CLI11')
endif

dependency_list = [CLI11_dep]
sdbusplus = dependency('sdbusplus', fallback: [ 'sdbusplus', 'sdbusplus_dep' ])
dependency_list = [CLI11_dep, sdbusplus]

sources = ['src/vpd_tool_main.cpp',
'src/vpd_tool.cpp']
Expand Down
76 changes: 67 additions & 9 deletions vpd-tool/src/vpd_tool.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,78 @@
#include "vpd_tool.hpp"

#include "tool_constants.hpp"
#include "tool_types.hpp"
#include "tool_utils.hpp"

#include <iostream>

extern bool VerboseMode;

namespace vpd
{
int VpdTool::readKeyword(const std::string& i_fruPath,
int VpdTool::readKeyword(const std::string& i_vpdPath,
const std::string& i_recordName,
const std::string& i_keywordName,
const bool i_onHardware,
const std::string& i_fileToSave)
{
// ToDo: Need to add implementation details
(void)i_fruPath;
(void)i_recordName;
(void)i_keywordName;
(void)i_onHardware;
(void)i_fileToSave;

return 0;
int l_rc = -1;
try
{
types::DbusVariantType l_keywordValue;
if (i_onHardware)
{
// TODO: Implement read keyword's value from hardware
}
else
{
std::string l_inventoryObjectPath(constants::baseInventoryPath +
i_vpdPath);

l_keywordValue = utils::readDbusProperty(
constants::inventoryManagerService, l_inventoryObjectPath,
constants::ipzVpdInfPrefix + i_recordName, i_keywordName);
}

if (const auto l_value =
std::get_if<types::BinaryVector>(&l_keywordValue);
l_value && !l_value->empty())
{
const std::string& l_keywordStrValue =
utils::getPrintableValue(*l_value);

if (i_fileToSave.empty())
{
nlohmann::json l_resultInJson = nlohmann::json::object({});
nlohmann::json l_keywordValInJson = nlohmann::json::object({});

l_keywordValInJson.emplace(i_keywordName, l_keywordStrValue);
l_resultInJson.emplace(i_vpdPath, l_keywordValInJson);

utils::printJson(l_resultInJson);
}
else
{
// TODO: Write result to a given file path.
}
l_rc = 0;
}
else if (VerboseMode)
{
std::cout << "Invalid data type or empty data received."
<< std::endl;
}
}
catch (const std::exception& l_ex)
{
if (VerboseMode)
{
std::cerr << "Read keyword's value for path: " << i_vpdPath
<< ", Record: " << i_recordName
<< ", Keyword: " << i_keywordName
<< " is failed, exception: " << l_ex.what() << std::endl;
}
}
return l_rc;
}
} // namespace vpd
43 changes: 30 additions & 13 deletions vpd-tool/src/vpd_tool_main.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#include "tool_constants.hpp"
#include "vpd_tool.hpp"

#include <CLI/CLI.hpp>

#include <filesystem>
#include <iostream>

bool VerboseMode = false;

int main(int argc, char** argv)
{
int l_rc = -1;
Expand Down Expand Up @@ -45,40 +48,54 @@ int main(int argc, char** argv)
auto l_hardwareFlag = l_app.add_flag("--Hardware, -H",
"CAUTION: Developer only option.");

auto l_verboseFlag = l_app.add_flag("--verbose, -v", "Enable Verbose Mode");

// ToDo: Take offset value from user for hardware path.

CLI11_PARSE(l_app, argc, argv);

if (*l_objectOption && l_vpdPath.empty())
if ((l_objectOption->count() > 0) && l_vpdPath.empty())
{
std::cout << "Given path is empty." << std::endl;
return -1;
return l_rc;
}

if (*l_recordOption && (l_recordName.size() != vpd::constants::RECORD_SIZE))
if ((l_recordOption->count() > 0) &&
(l_recordName.size() != vpd::constants::RECORD_SIZE))
{
std::cerr << "Record " << l_recordName << " is not supported."
<< std::endl;
return l_rc;
}

if (*l_keywordOption &&
if ((l_keywordOption->count() > 0) &&
(l_keywordName.size() != vpd::constants::KEYWORD_SIZE))
{
std::cerr << "Keyword " << l_keywordName << " is not supported."
<< std::endl;
return l_rc;
}

if (*l_hardwareFlag && !std::filesystem::exists(l_vpdPath))
{
std::cerr << "Given EEPROM file path doesn't exist : " + l_vpdPath
<< std::endl;
return l_rc;
}

(void)l_fileOption;

if (*l_readFlag)
VerboseMode = ((l_verboseFlag->count() > 0) ? true : false);

if (l_readFlag->count() > 0)
{
// TODO: call read keyword implementation from here.
if ((l_hardwareFlag->count() > 0) &&
!std::filesystem::exists(l_vpdPath))
{
std::cerr << "Given EEPROM file path doesn't exist : " + l_vpdPath
<< std::endl;
return l_rc;
}

bool l_isHardwareOperation = ((l_hardwareFlag->count() > 0) ? true
: false);
vpd::VpdTool l_vpdToolObj;

l_rc = l_vpdToolObj.readKeyword(l_vpdPath, l_recordName, l_keywordName,
l_isHardwareOperation, l_filePath);
}
else
{
Expand Down