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