blob: ac1fff7067dcd3feb158886966ed96caee27e89a [file] [log] [blame]
Brad Bishopf6783cd2020-10-27 19:25:09 -04001#include "create_pel.hpp"
2
3#include <fcntl.h>
4#include <fmt/format.h>
5#include <libekb.H>
6#include <unistd.h>
7
8#include <cerrno>
9#include <cstdio>
10#include <cstdlib>
11#include <cstring>
12#include <map>
13#include <phosphor-logging/elog.hpp>
14#include <stdexcept>
15#include <string>
16#include <tuple>
17#include <vector>
18#include <xyz/openbmc_project/Logging/Create/server.hpp>
19#include <xyz/openbmc_project/Logging/Entry/server.hpp>
20
21namespace openpower
22{
23using namespace phosphor::logging;
24
25namespace util
26{
27std::string getService(sdbusplus::bus::bus& bus, const std::string& objectPath,
28 const std::string& interface)
29{
30 constexpr auto mapperBusBame = "xyz.openbmc_project.ObjectMapper";
31 constexpr auto mapperObjectPath = "/xyz/openbmc_project/object_mapper";
32 constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper";
33 std::vector<std::pair<std::string, std::vector<std::string>>> response;
34 auto method = bus.new_method_call(mapperBusBame, mapperObjectPath,
35 mapperInterface, "GetObject");
36 method.append(objectPath, std::vector<std::string>({interface}));
37 try
38 {
39 auto reply = bus.call(method);
40 reply.read(response);
41 }
42 catch (const sdbusplus::exception::SdBusError& e)
43 {
44 log<level::ERR>("D-Bus call exception",
45 entry("OBJPATH=%s", mapperObjectPath),
46 entry("INTERFACE=%s", mapperInterface),
47 entry("EXCEPTION=%s", e.what()));
48
49 throw std::runtime_error("Service name is not found");
50 }
51
52 if (response.empty())
53 {
54 throw std::runtime_error("Service name response is empty");
55 }
56 return response.begin()->first;
57}
58} // namespace util
59
60namespace pel
61{
62void createBootErrorPEL(const FFDCData& ffdcData, const json& calloutData)
63{
64 constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
65 constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create";
66
67 std::map<std::string, std::string> additionalData;
68 auto bus = sdbusplus::bus::new_default();
69 additionalData.emplace("_PID", std::to_string(getpid()));
70 for (auto& data : ffdcData)
71 {
72 additionalData.emplace(data);
73 }
74
75 try
76 {
77 FFDCFile ffdcFile(calloutData);
78
79 std::vector<std::tuple<sdbusplus::xyz::openbmc_project::Logging::
80 server::Create::FFDCFormat,
81 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
82 pelCalloutInfo;
83
84 pelCalloutInfo.push_back(
85 std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server::
86 Create::FFDCFormat::JSON,
87 static_cast<uint8_t>(0xCA),
88 static_cast<uint8_t>(0x01), ffdcFile.getFileFD()));
89
90 static constexpr auto bootErrorMessage =
91 "org.open_power.PHAL.Error.Boot";
92 std::string service =
93 util::getService(bus, loggingObjectPath, loggingInterface);
94 auto method =
95 bus.new_method_call(service.c_str(), loggingObjectPath,
96 loggingInterface, "CreateWithFFDCFiles");
97 auto level =
98 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
99 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
100 Error);
101 method.append(bootErrorMessage, level, additionalData, pelCalloutInfo);
102 auto resp = bus.call(method);
103 }
104 catch (const sdbusplus::exception::SdBusError& e)
105 {
106 log<level::ERR>("D-Bus call exception",
107 entry("OBJPATH=%s", loggingObjectPath),
108 entry("INTERFACE=%s", loggingInterface),
109 entry("EXCEPTION=%s", e.what()));
110
111 throw std::runtime_error(
112 "Error in invoking D-Bus logging create interface");
113 }
114 catch (std::exception& e)
115 {
116 throw e;
117 }
118}
119
120FFDCFile::FFDCFile(const json& pHALCalloutData) :
121 calloutData(pHALCalloutData.dump()),
122 calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1)
123{
124 prepareFFDCFile();
125}
126
127FFDCFile::~FFDCFile()
128{
129 removeCalloutFile();
130}
131
132int FFDCFile::getFileFD() const
133{
134 return fileFD;
135}
136
137void FFDCFile::prepareFFDCFile()
138{
139 createCalloutFile();
140 writeCalloutData();
141 setCalloutFileSeekPos();
142}
143
144void FFDCFile::createCalloutFile()
145{
146 fileFD = mkostemp(const_cast<char*>(calloutFile.c_str()), O_RDWR);
147
148 if (fileFD == -1)
149 {
150 log<level::ERR>(fmt::format("Failed to create phalPELCallouts "
151 "file({}), errorno({}) and errormsg({})",
152 calloutFile, errno, strerror(errno))
153 .c_str());
154 throw std::runtime_error("Failed to create phalPELCallouts file");
155 }
156}
157
158void FFDCFile::writeCalloutData()
159{
160 ssize_t rc = write(fileFD, calloutData.c_str(), calloutData.size());
161
162 if (rc == -1)
163 {
164 log<level::ERR>(fmt::format("Failed to write phaPELCallout info "
165 "in file({}), errorno({}), errormsg({})",
166 calloutFile, errno, strerror(errno))
167 .c_str());
168 throw std::runtime_error("Failed to write phalPELCallouts info");
169 }
170 else if (rc != static_cast<ssize_t>(calloutData.size()))
171 {
172 log<level::WARNING>(fmt::format("Could not write all phal callout "
173 "info in file({}), written byte({}) "
174 "and total byte({})",
175 calloutFile, rc, calloutData.size())
176 .c_str());
177 }
178}
179
180void FFDCFile::setCalloutFileSeekPos()
181{
182 int rc = lseek(fileFD, 0, SEEK_SET);
183
184 if (rc == -1)
185 {
186 log<level::ERR>(fmt::format("Failed to set SEEK_SET for "
187 "phalPELCallouts in file({}), errorno({}) "
188 "and errormsg({})",
189 calloutFile, errno, strerror(errno))
190 .c_str());
191 throw std::runtime_error(
192 "Failed to set SEEK_SET for phalPELCallouts file");
193 }
194}
195
196void FFDCFile::removeCalloutFile()
197{
198 close(fileFD);
199 std::remove(calloutFile.c_str());
200}
201
202} // namespace pel
203} // namespace openpower