| #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 |