blob: 7fb19ef90efbb23bfddac31374cc88c33a8976b9 [file] [log] [blame]
Jason M. Bills5e049d32018-10-19 12:59:38 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include <systemd/sd-journal.h>
17
Jason M. Billsc4a336f2019-04-23 10:43:10 -070018#include <boost/algorithm/string.hpp>
Ed Tanous90926992020-09-11 12:59:33 -070019#include <boost/asio/io_service.hpp>
Jason M. Bills5e049d32018-10-19 12:59:38 -070020#include <boost/container/flat_map.hpp>
21#include <boost/container/flat_set.hpp>
Zhikui Ren672bdfc2020-07-14 11:37:01 -070022#include <pulse_event_monitor.hpp>
23#include <sdbusplus/asio/object_server.hpp>
24#include <sel_logger.hpp>
25#include <threshold_event_monitor.hpp>
26
Jason M. Billsc4a336f2019-04-23 10:43:10 -070027#include <filesystem>
28#include <fstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070029#include <iomanip>
30#include <iostream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070031#include <sstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070032
Lei YUe526b862020-12-03 15:41:59 +080033#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
34#include <phosphor-logging/elog-errors.hpp>
35#include <phosphor-logging/elog.hpp>
36#include <phosphor-logging/log.hpp>
37#include <xyz/openbmc_project/Logging/SEL/error.hpp>
38
39using namespace phosphor::logging;
40using SELCreated =
41 sdbusplus::xyz::openbmc_project::Logging::SEL::Error::Created;
42#endif
43
Jason M. Bills5e049d32018-10-19 12:59:38 -070044struct DBusInternalError final : public sdbusplus::exception_t
45{
Zhikui Ren672bdfc2020-07-14 11:37:01 -070046 const char* name() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070047 {
48 return "org.freedesktop.DBus.Error.Failed";
49 };
Zhikui Ren672bdfc2020-07-14 11:37:01 -070050 const char* description() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070051 {
52 return "internal error";
53 };
Zhikui Ren672bdfc2020-07-14 11:37:01 -070054 const char* what() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070055 {
56 return "org.freedesktop.DBus.Error.Failed: "
57 "internal error";
58 };
59};
60
Lei YUe526b862020-12-03 15:41:59 +080061#ifndef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
Zhikui Ren672bdfc2020-07-14 11:37:01 -070062static bool getSELLogFiles(std::vector<std::filesystem::path>& selLogFiles)
Jason M. Billsc4a336f2019-04-23 10:43:10 -070063{
64 // Loop through the directory looking for ipmi_sel log files
Zhikui Ren672bdfc2020-07-14 11:37:01 -070065 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Billsc4a336f2019-04-23 10:43:10 -070066 std::filesystem::directory_iterator(selLogDir))
67 {
68 std::string filename = dirEnt.path().filename();
69 if (boost::starts_with(filename, selLogFilename))
70 {
71 // If we find an ipmi_sel log file, save the path
72 selLogFiles.emplace_back(selLogDir / filename);
73 }
74 }
75 // As the log files rotate, they are appended with a ".#" that is higher for
76 // the older logs. Since we don't expect more than 10 log files, we
77 // can just sort the list to get them in order from newest to oldest
78 std::sort(selLogFiles.begin(), selLogFiles.end());
79
80 return !selLogFiles.empty();
81}
82
Jason M. Bills5e049d32018-10-19 12:59:38 -070083static unsigned int initializeRecordId(void)
84{
Jason M. Billsc4a336f2019-04-23 10:43:10 -070085 std::vector<std::filesystem::path> selLogFiles;
86 if (!getSELLogFiles(selLogFiles))
Jason M. Bills5e049d32018-10-19 12:59:38 -070087 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -070088 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -070089 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -070090 std::ifstream logStream(selLogFiles.front());
91 if (!logStream.is_open())
Jason M. Bills5e049d32018-10-19 12:59:38 -070092 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -070093 return selInvalidRecID;
94 }
95 std::string line;
96 std::string newestEntry;
97 while (std::getline(logStream, line))
98 {
99 newestEntry = line;
100 }
Jason M. Bills5e049d32018-10-19 12:59:38 -0700101
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700102 std::vector<std::string> newestEntryFields;
103 boost::split(newestEntryFields, newestEntry, boost::is_any_of(" ,"),
104 boost::token_compress_on);
105 if (newestEntryFields.size() < 4)
106 {
107 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700108 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700109
110 return std::stoul(newestEntryFields[1]);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700111}
112
113static unsigned int getNewRecordId(void)
114{
115 static unsigned int recordId = initializeRecordId();
116
Jason M. Bills6afe9562019-08-29 16:33:55 -0700117 // If the log has been cleared, also clear the current ID
118 std::vector<std::filesystem::path> selLogFiles;
119 if (!getSELLogFiles(selLogFiles))
120 {
121 recordId = selInvalidRecID;
122 }
123
Jason M. Bills5e049d32018-10-19 12:59:38 -0700124 if (++recordId >= selInvalidRecID)
125 {
126 recordId = 1;
127 }
128 return recordId;
129}
Lei YUe526b862020-12-03 15:41:59 +0800130#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700131
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700132static void toHexStr(const std::vector<uint8_t>& data, std::string& hexStr)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700133{
134 std::stringstream stream;
135 stream << std::hex << std::uppercase << std::setfill('0');
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700136 for (const int& v : data)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700137 {
138 stream << std::setw(2) << v;
139 }
140 hexStr = stream.str();
141}
142
Jason M. Bills97be3532018-11-02 13:09:16 -0700143template <typename... T>
144static uint16_t
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700145 selAddSystemRecord(const std::string& message, const std::string& path,
146 const std::vector<uint8_t>& selData, const bool& assert,
147 const uint16_t& genId, T&&... metadata)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700148{
149 // Only 3 bytes of SEL event data are allowed in a system record
150 if (selData.size() > selEvtDataMaxSize)
151 {
152 throw std::invalid_argument("Event data too large");
153 }
154 std::string selDataStr;
155 toHexStr(selData, selDataStr);
156
Lei YUe526b862020-12-03 15:41:59 +0800157#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
158 using namespace xyz::openbmc_project::Logging::SEL;
159 report<SELCreated>(
160 Created::RECORD_TYPE(selSystemType), Created::GENERATOR_ID(genId),
161 Created::SENSOR_DATA(selDataStr.c_str()), Created::EVENT_DIR(assert),
162 Created::SENSOR_PATH(path.c_str()));
163 return 0;
164#else
Jason M. Bills5e049d32018-10-19 12:59:38 -0700165 unsigned int recordId = getNewRecordId();
Jason M. Bills97be3532018-11-02 13:09:16 -0700166 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
167 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
168 recordId, "IPMI_SEL_RECORD_TYPE=%x", selSystemType,
169 "IPMI_SEL_GENERATOR_ID=%x", genId,
170 "IPMI_SEL_SENSOR_PATH=%s", path.c_str(),
171 "IPMI_SEL_EVENT_DIR=%x", assert, "IPMI_SEL_DATA=%s",
172 selDataStr.c_str(), std::forward<T>(metadata)..., NULL);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700173 return recordId;
Lei YUe526b862020-12-03 15:41:59 +0800174#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700175}
176
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700177static uint16_t selAddOemRecord(const std::string& message,
178 const std::vector<uint8_t>& selData,
179 const uint8_t& recordType)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700180{
181 // A maximum of 13 bytes of SEL event data are allowed in an OEM record
182 if (selData.size() > selOemDataMaxSize)
183 {
184 throw std::invalid_argument("Event data too large");
185 }
186 std::string selDataStr;
187 toHexStr(selData, selDataStr);
188
Lei YUe526b862020-12-03 15:41:59 +0800189#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
190 using namespace xyz::openbmc_project::Logging::SEL;
191 report<SELCreated>(Created::RECORD_TYPE(recordType),
192 Created::GENERATOR_ID(0),
193 Created::SENSOR_DATA(selDataStr.c_str()),
194 Created::EVENT_DIR(0), Created::SENSOR_PATH(""));
195 return 0;
196#else
Jason M. Bills5e049d32018-10-19 12:59:38 -0700197 unsigned int recordId = getNewRecordId();
198 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
199 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
200 recordId, "IPMI_SEL_RECORD_TYPE=%x", recordType,
201 "IPMI_SEL_DATA=%s", selDataStr.c_str(), NULL);
202 return recordId;
Lei YUe526b862020-12-03 15:41:59 +0800203#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700204}
205
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700206int main(int argc, char* argv[])
Jason M. Bills5e049d32018-10-19 12:59:38 -0700207{
208 // setup connection to dbus
209 boost::asio::io_service io;
210 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
211
212 // IPMI SEL Object
213 conn->request_name(ipmiSelObject);
214 auto server = sdbusplus::asio::object_server(conn);
215
216 // Add SEL Interface
217 std::shared_ptr<sdbusplus::asio::dbus_interface> ifaceAddSel =
218 server.add_interface(ipmiSelPath, ipmiSelAddInterface);
219
220 // Add a new SEL entry
221 ifaceAddSel->register_method(
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700222 "IpmiSelAdd", [](const std::string& message, const std::string& path,
223 const std::vector<uint8_t>& selData,
224 const bool& assert, const uint16_t& genId) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700225 return selAddSystemRecord(message, path, selData, assert, genId);
226 });
227 // Add a new OEM SEL entry
228 ifaceAddSel->register_method(
229 "IpmiSelAddOem",
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700230 [](const std::string& message, const std::vector<uint8_t>& selData,
231 const uint8_t& recordType) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700232 return selAddOemRecord(message, selData, recordType);
233 });
234 ifaceAddSel->initialize();
235
236#ifdef SEL_LOGGER_MONITOR_THRESHOLD_EVENTS
Zhikui Ren25b26e12020-06-26 20:18:19 -0700237 sdbusplus::bus::match::match thresholdAssertMonitor =
238 startThresholdAssertMonitor(conn);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700239#endif
240
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800241#ifdef REDFISH_LOG_MONITOR_PULSE_EVENTS
242 sdbusplus::bus::match::match pulseEventMonitor =
243 startPulseEventMonitor(conn);
244#endif
245
Jason M. Bills5e049d32018-10-19 12:59:38 -0700246 io.run();
247
248 return 0;
249}