Brad Bishop | f6783cd | 2020-10-27 19:25:09 -0400 | [diff] [blame] | 1 | #include "create_pel.hpp" |
| 2 | |
| 3 | #include <fcntl.h> |
| 4 | #include <fmt/format.h> |
| 5 | #include <libekb.H> |
| 6 | #include <unistd.h> |
| 7 | |
Brad Bishop | 5e5d445 | 2020-10-27 19:46:13 -0400 | [diff] [blame^] | 8 | #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 Bishop | f6783cd | 2020-10-27 19:25:09 -0400 | [diff] [blame] | 12 | #include <cerrno> |
| 13 | #include <cstdio> |
| 14 | #include <cstdlib> |
| 15 | #include <cstring> |
| 16 | #include <map> |
Brad Bishop | f6783cd | 2020-10-27 19:25:09 -0400 | [diff] [blame] | 17 | #include <stdexcept> |
| 18 | #include <string> |
| 19 | #include <tuple> |
| 20 | #include <vector> |
Brad Bishop | f6783cd | 2020-10-27 19:25:09 -0400 | [diff] [blame] | 21 | |
| 22 | namespace openpower |
| 23 | { |
| 24 | using namespace phosphor::logging; |
| 25 | |
| 26 | namespace util |
| 27 | { |
| 28 | std::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 | |
| 61 | namespace pel |
| 62 | { |
| 63 | void 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 | |
| 121 | FFDCFile::FFDCFile(const json& pHALCalloutData) : |
| 122 | calloutData(pHALCalloutData.dump()), |
| 123 | calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1) |
| 124 | { |
| 125 | prepareFFDCFile(); |
| 126 | } |
| 127 | |
| 128 | FFDCFile::~FFDCFile() |
| 129 | { |
| 130 | removeCalloutFile(); |
| 131 | } |
| 132 | |
| 133 | int FFDCFile::getFileFD() const |
| 134 | { |
| 135 | return fileFD; |
| 136 | } |
| 137 | |
| 138 | void FFDCFile::prepareFFDCFile() |
| 139 | { |
| 140 | createCalloutFile(); |
| 141 | writeCalloutData(); |
| 142 | setCalloutFileSeekPos(); |
| 143 | } |
| 144 | |
| 145 | void 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 | |
| 159 | void 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 | |
| 181 | void 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 | |
| 197 | void FFDCFile::removeCalloutFile() |
| 198 | { |
| 199 | close(fileFD); |
| 200 | std::remove(calloutFile.c_str()); |
| 201 | } |
| 202 | |
| 203 | } // namespace pel |
| 204 | } // namespace openpower |