blob: 2f8a057385e392545527a2ef53e4f0eda836d107 [file] [log] [blame]
#include "blob_handler.hpp"
#include <boot_time.pb.h>
#include <fmt/printf.h>
#include <sdbusplus/bus.hpp>
#include <cstdint>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
namespace blobs
{
using CheckpointType = std::vector<std::tuple<std::string, int64_t, int64_t>>;
using DurationType = std::vector<std::tuple<std::string, int64_t>>;
constexpr static std::string_view kHostBlobPath = "/btm/host/0";
constexpr static std::string_view kBMCBlobPath = "/btm/bmc";
namespace BootTimeMonitor
{
constexpr std::string_view kService = "com.google.gbmc.boot_time_monitor";
constexpr std::string_view kHostPath = "/xyz/openbmc_project/time/boot/host0";
constexpr std::string_view kBMCPath = "/xyz/openbmc_project/time/boot/bmc";
} // namespace BootTimeMonitor
namespace Checkpoint
{
constexpr std::string_view kIface = "xyz.openbmc_project.Time.Boot.Checkpoint";
constexpr std::string_view kMethod = "GetCheckpointList";
} // namespace Checkpoint
namespace Duration
{
constexpr std::string_view kIface = "xyz.openbmc_project.Time.Boot.Duration";
constexpr std::string_view kMethod = "GetAdditionalDurations";
} // namespace Duration
namespace Statistic
{
constexpr std::string_view kIface = "org.freedesktop.DBus.Properties";
constexpr std::string_view kMethod = "Get";
constexpr std::string_view kParam1 = "xyz.openbmc_project.Time.Boot.Statistic";
constexpr std::string_view kParam2 = "IsRebooting";
} // namespace Statistic
bool BlobHandler::canHandleBlob(const std::string& path)
{
return (path == kHostBlobPath) || (path == kBMCBlobPath);
}
// A blob handler may have multiple Blobs.
std::vector<std::string> BlobHandler::getBlobIds()
{
return {kHostBlobPath.data(), kBMCBlobPath.data()};
}
// BmcBlobDelete (7) is not supported.
bool BlobHandler::deleteBlob([[maybe_unused]] const std::string& path)
{
return false;
}
// BmcBlobStat (8) (global stat) is not supported.
bool BlobHandler::stat([[maybe_unused]] const std::string& path,
[[maybe_unused]] BlobMeta* meta)
{
return false;
}
// BmcBlobOpen(2) handler.
bool BlobHandler::open(uint16_t session, uint16_t flags,
const std::string& path)
{
if (!isReadOnlyOpenFlags(flags))
{
fmt::print(stderr, "[{}] Flag is not read-only. flag={}\n",
__FUNCTION__, flags);
return false;
}
if (!canHandleBlob(path))
{
fmt::print(stderr, "[{}] Can't handle path={}\n", __FUNCTION__, path);
return false;
}
sdbusplus::bus_t bus = sdbusplus::bus::new_default();
boottimeproto::BootTime btProto;
std::string btmPath;
if (path == kBMCBlobPath)
{
btmPath = BootTimeMonitor::kBMCPath;
}
else
{
btmPath = BootTimeMonitor::kHostPath;
}
// Get checkpoints
try
{
auto method = bus.new_method_call(
BootTimeMonitor::kService.data(), btmPath.c_str(),
Checkpoint::kIface.data(), Checkpoint::kMethod.data());
CheckpointType checkpoints;
bus.call(method).read(checkpoints);
for (auto checkpoint : checkpoints)
{
auto cpProto = btProto.add_checkpoints();
cpProto->set_name(std::get<0>(checkpoint));
cpProto->set_wall_time_ms(std::get<1>(checkpoint));
cpProto->set_mono_time_ms(std::get<2>(checkpoint));
}
}
catch (const sdbusplus::exception::SdBusError& e)
{
fmt::print(
stderr,
"[{}] Failed in method call. service={}, path={}, Iface={}, method={}, error={}\n",
__FUNCTION__, BootTimeMonitor::kService.data(), btmPath.c_str(),
Checkpoint::kIface.data(), Checkpoint::kMethod.data(), e.what());
return false;
}
// Get durations
try
{
auto method = bus.new_method_call(
BootTimeMonitor::kService.data(), btmPath.c_str(),
Duration::kIface.data(), Duration::kMethod.data());
DurationType durations;
bus.call(method).read(durations);
for (auto duration : durations)
{
auto durProto = btProto.add_durations();
durProto->set_name(std::get<0>(duration));
durProto->set_duration_ms(std::get<1>(duration));
}
}
catch (const sdbusplus::exception::SdBusError& e)
{
fmt::print(
stderr,
"[{}] Failed in method call. service={}, path={}, Iface={}, method={}, error={}\n",
__FUNCTION__, BootTimeMonitor::kService.data(), btmPath.c_str(),
Duration::kIface.data(), Duration::kMethod.data(), e.what());
return false;
}
// Get `IsRebooting`
try
{
auto method = bus.new_method_call(
BootTimeMonitor::kService.data(), btmPath.c_str(),
Statistic::kIface.data(), Statistic::kMethod.data());
method.append(Statistic::kParam1.data(), Statistic::kParam2.data());
std::variant<bool> isRebooting;
bus.call(method).read(isRebooting);
btProto.set_is_rebooting(std::get<bool>(isRebooting));
}
catch (const sdbusplus::exception::SdBusError& e)
{
fmt::print(
stderr,
"[{}] Failed in method call. service={}, path={}, Iface={}, method={}, param1={}, param2={}, error={}\n",
__FUNCTION__, BootTimeMonitor::kService.data(), btmPath.c_str(),
Statistic::kIface.data(), Statistic::kMethod.data(),
Statistic::kParam1.data(), Statistic::kParam2.data(), e.what());
return false;
}
std::vector<char> vec(btProto.ByteSizeLong());
if (!btProto.SerializeToArray(vec.data(), vec.size()))
{
fmt::print(stderr, "[{}]: Could not serialize protobuf to array\n",
__FUNCTION__);
return false;
}
sessions[session] = std::move(vec);
return true;
}
// BmcBlobRead(3) handler.
std::vector<uint8_t> BlobHandler::read(uint16_t session, uint32_t offset,
uint32_t requestedSize)
{
auto it = sessions.find(session);
if (it == sessions.end())
{
return {};
}
if (offset + requestedSize > it->second.size())
{
return std::vector<uint8_t>(it->second.data() + offset,
it->second.data() + it->second.size());
}
return std::vector<uint8_t>(it->second.data() + offset,
it->second.data() + offset + requestedSize);
}
// BmcBlobWrite(4) is not supported.
bool BlobHandler::write([[maybe_unused]] uint16_t session,
[[maybe_unused]] uint32_t offset,
[[maybe_unused]] const std::vector<uint8_t>& data)
{
return false;
}
// BmcBlobWriteMeta(10) is not supported.
bool BlobHandler::writeMeta([[maybe_unused]] uint16_t session,
[[maybe_unused]] uint32_t offset,
[[maybe_unused]] const std::vector<uint8_t>& data)
{
return false;
}
// BmcBlobCommit(5) is not supported.
bool BlobHandler::commit([[maybe_unused]] uint16_t session,
[[maybe_unused]] const std::vector<uint8_t>& data)
{
return false;
}
// BmcBlobClose(6) handler.
bool BlobHandler::close(uint16_t session)
{
auto itr = sessions.find(session);
if (itr == sessions.end())
{
return false;
}
sessions.erase(itr);
return true;
}
bool BlobHandler::stat(uint16_t session, BlobMeta* meta)
{
auto it = sessions.find(session);
if (it == sessions.end())
{
return false;
}
meta->size = it->second.size();
meta->blobState = blobs::StateFlags::open_read;
return true;
}
bool BlobHandler::expire(uint16_t session)
{
return close(session);
}
// Checks for a read-only flag.
bool BlobHandler::isReadOnlyOpenFlags(const uint16_t flags)
{
if (((flags & blobs::OpenFlags::read) == blobs::OpenFlags::read) &&
((flags & blobs::OpenFlags::write) == 0))
{
return true;
}
return false;
}
} // namespace blobs