#include "create_pel.hpp" | |
#include <fcntl.h> | |
#include <fmt/format.h> | |
#include <libekb.H> | |
#include <unistd.h> | |
#include <cerrno> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cstring> | |
#include <map> | |
#include <phosphor-logging/elog.hpp> | |
#include <stdexcept> | |
#include <string> | |
#include <tuple> | |
#include <vector> | |
#include <xyz/openbmc_project/Logging/Create/server.hpp> | |
#include <xyz/openbmc_project/Logging/Entry/server.hpp> | |
namespace openpower | |
{ | |
using namespace phosphor::logging; | |
namespace util | |
{ | |
std::string getService(sdbusplus::bus::bus& bus, const std::string& objectPath, | |
const std::string& interface) | |
{ | |
constexpr auto mapperBusBame = "xyz.openbmc_project.ObjectMapper"; | |
constexpr auto mapperObjectPath = "/xyz/openbmc_project/object_mapper"; | |
constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper"; | |
std::vector<std::pair<std::string, std::vector<std::string>>> response; | |
auto method = bus.new_method_call(mapperBusBame, mapperObjectPath, | |
mapperInterface, "GetObject"); | |
method.append(objectPath, std::vector<std::string>({interface})); | |
try | |
{ | |
auto reply = bus.call(method); | |
reply.read(response); | |
} | |
catch (const sdbusplus::exception::SdBusError& e) | |
{ | |
log<level::ERR>("D-Bus call exception", | |
entry("OBJPATH=%s", mapperObjectPath), | |
entry("INTERFACE=%s", mapperInterface), | |
entry("EXCEPTION=%s", e.what())); | |
throw std::runtime_error("Service name is not found"); | |
} | |
if (response.empty()) | |
{ | |
throw std::runtime_error("Service name response is empty"); | |
} | |
return response.begin()->first; | |
} | |
} // namespace util | |
namespace pel | |
{ | |
void createBootErrorPEL(const FFDCData& ffdcData, const json& calloutData) | |
{ | |
constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging"; | |
constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create"; | |
std::map<std::string, std::string> additionalData; | |
auto bus = sdbusplus::bus::new_default(); | |
additionalData.emplace("_PID", std::to_string(getpid())); | |
for (auto& data : ffdcData) | |
{ | |
additionalData.emplace(data); | |
} | |
try | |
{ | |
FFDCFile ffdcFile(calloutData); | |
std::vector<std::tuple<sdbusplus::xyz::openbmc_project::Logging:: | |
server::Create::FFDCFormat, | |
uint8_t, uint8_t, sdbusplus::message::unix_fd>> | |
pelCalloutInfo; | |
pelCalloutInfo.push_back( | |
std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server:: | |
Create::FFDCFormat::JSON, | |
static_cast<uint8_t>(0xCA), | |
static_cast<uint8_t>(0x01), ffdcFile.getFileFD())); | |
static constexpr auto bootErrorMessage = | |
"org.open_power.PHAL.Error.Boot"; | |
std::string service = | |
util::getService(bus, loggingObjectPath, loggingInterface); | |
auto method = | |
bus.new_method_call(service.c_str(), loggingObjectPath, | |
loggingInterface, "CreateWithFFDCFiles"); | |
auto level = | |
sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( | |
sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: | |
Error); | |
method.append(bootErrorMessage, level, additionalData, pelCalloutInfo); | |
auto resp = bus.call(method); | |
} | |
catch (const sdbusplus::exception::SdBusError& e) | |
{ | |
log<level::ERR>("D-Bus call exception", | |
entry("OBJPATH=%s", loggingObjectPath), | |
entry("INTERFACE=%s", loggingInterface), | |
entry("EXCEPTION=%s", e.what())); | |
throw std::runtime_error( | |
"Error in invoking D-Bus logging create interface"); | |
} | |
catch (std::exception& e) | |
{ | |
throw e; | |
} | |
} | |
FFDCFile::FFDCFile(const json& pHALCalloutData) : | |
calloutData(pHALCalloutData.dump()), | |
calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1) | |
{ | |
prepareFFDCFile(); | |
} | |
FFDCFile::~FFDCFile() | |
{ | |
removeCalloutFile(); | |
} | |
int FFDCFile::getFileFD() const | |
{ | |
return fileFD; | |
} | |
void FFDCFile::prepareFFDCFile() | |
{ | |
createCalloutFile(); | |
writeCalloutData(); | |
setCalloutFileSeekPos(); | |
} | |
void FFDCFile::createCalloutFile() | |
{ | |
fileFD = mkostemp(const_cast<char*>(calloutFile.c_str()), O_RDWR); | |
if (fileFD == -1) | |
{ | |
log<level::ERR>(fmt::format("Failed to create phalPELCallouts " | |
"file({}), errorno({}) and errormsg({})", | |
calloutFile, errno, strerror(errno)) | |
.c_str()); | |
throw std::runtime_error("Failed to create phalPELCallouts file"); | |
} | |
} | |
void FFDCFile::writeCalloutData() | |
{ | |
ssize_t rc = write(fileFD, calloutData.c_str(), calloutData.size()); | |
if (rc == -1) | |
{ | |
log<level::ERR>(fmt::format("Failed to write phaPELCallout info " | |
"in file({}), errorno({}), errormsg({})", | |
calloutFile, errno, strerror(errno)) | |
.c_str()); | |
throw std::runtime_error("Failed to write phalPELCallouts info"); | |
} | |
else if (rc != static_cast<ssize_t>(calloutData.size())) | |
{ | |
log<level::WARNING>(fmt::format("Could not write all phal callout " | |
"info in file({}), written byte({}) " | |
"and total byte({})", | |
calloutFile, rc, calloutData.size()) | |
.c_str()); | |
} | |
} | |
void FFDCFile::setCalloutFileSeekPos() | |
{ | |
int rc = lseek(fileFD, 0, SEEK_SET); | |
if (rc == -1) | |
{ | |
log<level::ERR>(fmt::format("Failed to set SEEK_SET for " | |
"phalPELCallouts in file({}), errorno({}) " | |
"and errormsg({})", | |
calloutFile, errno, strerror(errno)) | |
.c_str()); | |
throw std::runtime_error( | |
"Failed to set SEEK_SET for phalPELCallouts file"); | |
} | |
} | |
void FFDCFile::removeCalloutFile() | |
{ | |
close(fileFD); | |
std::remove(calloutFile.c_str()); | |
} | |
} // namespace pel | |
} // namespace openpower |