blob: 6798682c52060a805205f8f878db964ea1326094 [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>
Charles Hsudbd77b92020-10-29 11:20:34 +080026#include <watchdog_event_monitor.hpp>
George Hung486e42e2021-04-14 20:20:42 +080027#ifdef SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
28#include <threshold_alarm_event_monitor.hpp>
29#endif
JinFuLin7c2810b2022-12-02 13:55:28 +080030#ifdef SEL_LOGGER_MONITOR_HOST_ERROR_EVENTS
31#include <host_error_event_monitor.hpp>
32#endif
Zhikui Ren672bdfc2020-07-14 11:37:01 -070033
Jason M. Billsc4a336f2019-04-23 10:43:10 -070034#include <filesystem>
35#include <fstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070036#include <iomanip>
37#include <iostream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070038#include <sstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070039
Lei YUe526b862020-12-03 15:41:59 +080040#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
41#include <phosphor-logging/elog-errors.hpp>
42#include <phosphor-logging/elog.hpp>
43#include <phosphor-logging/log.hpp>
44#include <xyz/openbmc_project/Logging/SEL/error.hpp>
45
46using namespace phosphor::logging;
47using SELCreated =
48 sdbusplus::xyz::openbmc_project::Logging::SEL::Error::Created;
49#endif
50
Jason M. Bills5e049d32018-10-19 12:59:38 -070051struct DBusInternalError final : public sdbusplus::exception_t
52{
Zhikui Ren672bdfc2020-07-14 11:37:01 -070053 const char* name() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070054 {
55 return "org.freedesktop.DBus.Error.Failed";
Patrick Williamsa138ebd2021-09-08 15:46:34 -050056 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -070057 const char* description() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070058 {
59 return "internal error";
Patrick Williamsa138ebd2021-09-08 15:46:34 -050060 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -070061 const char* what() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070062 {
63 return "org.freedesktop.DBus.Error.Failed: "
64 "internal error";
Patrick Williamsa138ebd2021-09-08 15:46:34 -050065 }
66
67 int get_errno() const noexcept override
68 {
69 return EACCES;
70 }
Jason M. Bills5e049d32018-10-19 12:59:38 -070071};
72
Lei YUe526b862020-12-03 15:41:59 +080073#ifndef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
Zhikui Ren672bdfc2020-07-14 11:37:01 -070074static bool getSELLogFiles(std::vector<std::filesystem::path>& selLogFiles)
Jason M. Billsc4a336f2019-04-23 10:43:10 -070075{
76 // Loop through the directory looking for ipmi_sel log files
Zhikui Ren672bdfc2020-07-14 11:37:01 -070077 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Billsc4a336f2019-04-23 10:43:10 -070078 std::filesystem::directory_iterator(selLogDir))
79 {
80 std::string filename = dirEnt.path().filename();
81 if (boost::starts_with(filename, selLogFilename))
82 {
83 // If we find an ipmi_sel log file, save the path
84 selLogFiles.emplace_back(selLogDir / filename);
85 }
86 }
87 // As the log files rotate, they are appended with a ".#" that is higher for
88 // the older logs. Since we don't expect more than 10 log files, we
89 // can just sort the list to get them in order from newest to oldest
90 std::sort(selLogFiles.begin(), selLogFiles.end());
91
92 return !selLogFiles.empty();
93}
94
Jason M. Bills5e049d32018-10-19 12:59:38 -070095static unsigned int initializeRecordId(void)
96{
Jason M. Billsc4a336f2019-04-23 10:43:10 -070097 std::vector<std::filesystem::path> selLogFiles;
98 if (!getSELLogFiles(selLogFiles))
Jason M. Bills5e049d32018-10-19 12:59:38 -070099 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700100 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700101 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700102 std::ifstream logStream(selLogFiles.front());
103 if (!logStream.is_open())
Jason M. Bills5e049d32018-10-19 12:59:38 -0700104 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700105 return selInvalidRecID;
106 }
107 std::string line;
108 std::string newestEntry;
109 while (std::getline(logStream, line))
110 {
111 newestEntry = line;
112 }
Jason M. Bills5e049d32018-10-19 12:59:38 -0700113
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700114 std::vector<std::string> newestEntryFields;
115 boost::split(newestEntryFields, newestEntry, boost::is_any_of(" ,"),
116 boost::token_compress_on);
117 if (newestEntryFields.size() < 4)
118 {
119 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700120 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700121
122 return std::stoul(newestEntryFields[1]);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700123}
124
Charles Boyer9f476e82021-07-29 16:33:01 -0500125#ifdef SEL_LOGGER_CLEARS_SEL
126static unsigned int recordId = initializeRecordId();
127
128void clearSelLogFiles()
129{
130 // Clear the SEL by deleting the log files
131 std::vector<std::filesystem::path> selLogFiles;
132 if (getSELLogFiles(selLogFiles))
133 {
134 for (const std::filesystem::path& file : selLogFiles)
135 {
136 std::error_code ec;
137 std::filesystem::remove(file, ec);
138 }
139 }
140
141 recordId = selInvalidRecID;
142
143 // Reload rsyslog so it knows to start new log files
144 boost::asio::io_service io;
145 auto dbus = std::make_shared<sdbusplus::asio::connection>(io);
Patrick Williamsccef2272022-07-22 19:26:54 -0500146 sdbusplus::message_t rsyslogReload = dbus->new_method_call(
Charles Boyer9f476e82021-07-29 16:33:01 -0500147 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
148 "org.freedesktop.systemd1.Manager", "ReloadUnit");
149 rsyslogReload.append("rsyslog.service", "replace");
150 try
151 {
Patrick Williamsccef2272022-07-22 19:26:54 -0500152 sdbusplus::message_t reloadResponse = dbus->call(rsyslogReload);
Charles Boyer9f476e82021-07-29 16:33:01 -0500153 }
Patrick Williams3f4cd972021-10-06 12:42:50 -0500154 catch (const sdbusplus::exception_t& e)
Charles Boyer9f476e82021-07-29 16:33:01 -0500155 {
156 std::cerr << e.what() << "\n";
157 }
158}
159#endif
160
Jason M. Bills5e049d32018-10-19 12:59:38 -0700161static unsigned int getNewRecordId(void)
162{
Charles Boyer9f476e82021-07-29 16:33:01 -0500163#ifndef SEL_LOGGER_CLEARS_SEL
Jason M. Bills5e049d32018-10-19 12:59:38 -0700164 static unsigned int recordId = initializeRecordId();
165
Jason M. Bills6afe9562019-08-29 16:33:55 -0700166 // If the log has been cleared, also clear the current ID
167 std::vector<std::filesystem::path> selLogFiles;
168 if (!getSELLogFiles(selLogFiles))
169 {
170 recordId = selInvalidRecID;
171 }
Charles Boyer9f476e82021-07-29 16:33:01 -0500172#endif
Jason M. Bills6afe9562019-08-29 16:33:55 -0700173
Jason M. Bills5e049d32018-10-19 12:59:38 -0700174 if (++recordId >= selInvalidRecID)
175 {
176 recordId = 1;
177 }
178 return recordId;
179}
Lei YUe526b862020-12-03 15:41:59 +0800180#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700181
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700182static void toHexStr(const std::vector<uint8_t>& data, std::string& hexStr)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700183{
184 std::stringstream stream;
185 stream << std::hex << std::uppercase << std::setfill('0');
William A. Kennington III2e437262021-07-30 12:04:19 -0700186 for (int v : data)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700187 {
188 stream << std::setw(2) << v;
189 }
190 hexStr = stream.str();
191}
192
Jason M. Bills97be3532018-11-02 13:09:16 -0700193template <typename... T>
William A. Kennington IIId585c592021-07-30 12:10:25 -0700194static uint16_t selAddSystemRecord([[maybe_unused]] const std::string& message,
195 const std::string& path,
196 const std::vector<uint8_t>& selData,
197 const bool& assert, const uint16_t& genId,
198 [[maybe_unused]] T&&... metadata)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700199{
200 // Only 3 bytes of SEL event data are allowed in a system record
201 if (selData.size() > selEvtDataMaxSize)
202 {
203 throw std::invalid_argument("Event data too large");
204 }
205 std::string selDataStr;
206 toHexStr(selData, selDataStr);
207
Lei YUe526b862020-12-03 15:41:59 +0800208#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
209 using namespace xyz::openbmc_project::Logging::SEL;
Lei YU7d8a3002021-01-21 17:16:19 +0800210 auto entryID = report<SELCreated>(
Lei YUe526b862020-12-03 15:41:59 +0800211 Created::RECORD_TYPE(selSystemType), Created::GENERATOR_ID(genId),
212 Created::SENSOR_DATA(selDataStr.c_str()), Created::EVENT_DIR(assert),
213 Created::SENSOR_PATH(path.c_str()));
Lei YU7d8a3002021-01-21 17:16:19 +0800214 return static_cast<uint16_t>(entryID);
Lei YUe526b862020-12-03 15:41:59 +0800215#else
Jason M. Bills5e049d32018-10-19 12:59:38 -0700216 unsigned int recordId = getNewRecordId();
Jason M. Bills97be3532018-11-02 13:09:16 -0700217 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
218 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
219 recordId, "IPMI_SEL_RECORD_TYPE=%x", selSystemType,
220 "IPMI_SEL_GENERATOR_ID=%x", genId,
221 "IPMI_SEL_SENSOR_PATH=%s", path.c_str(),
222 "IPMI_SEL_EVENT_DIR=%x", assert, "IPMI_SEL_DATA=%s",
223 selDataStr.c_str(), std::forward<T>(metadata)..., NULL);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700224 return recordId;
Lei YUe526b862020-12-03 15:41:59 +0800225#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700226}
227
William A. Kennington IIId585c592021-07-30 12:10:25 -0700228static uint16_t selAddOemRecord([[maybe_unused]] const std::string& message,
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700229 const std::vector<uint8_t>& selData,
230 const uint8_t& recordType)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700231{
232 // A maximum of 13 bytes of SEL event data are allowed in an OEM record
233 if (selData.size() > selOemDataMaxSize)
234 {
235 throw std::invalid_argument("Event data too large");
236 }
237 std::string selDataStr;
238 toHexStr(selData, selDataStr);
239
Lei YUe526b862020-12-03 15:41:59 +0800240#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
241 using namespace xyz::openbmc_project::Logging::SEL;
Lei YU7d8a3002021-01-21 17:16:19 +0800242 auto entryID = report<SELCreated>(
243 Created::RECORD_TYPE(recordType), Created::GENERATOR_ID(0),
244 Created::SENSOR_DATA(selDataStr.c_str()), Created::EVENT_DIR(0),
245 Created::SENSOR_PATH(""));
246 return static_cast<uint16_t>(entryID);
Lei YUe526b862020-12-03 15:41:59 +0800247#else
Jason M. Bills5e049d32018-10-19 12:59:38 -0700248 unsigned int recordId = getNewRecordId();
249 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
250 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
251 recordId, "IPMI_SEL_RECORD_TYPE=%x", recordType,
252 "IPMI_SEL_DATA=%s", selDataStr.c_str(), NULL);
253 return recordId;
Lei YUe526b862020-12-03 15:41:59 +0800254#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700255}
256
William A. Kennington IIId585c592021-07-30 12:10:25 -0700257int main(int, char*[])
Jason M. Bills5e049d32018-10-19 12:59:38 -0700258{
259 // setup connection to dbus
260 boost::asio::io_service io;
261 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
262
263 // IPMI SEL Object
264 conn->request_name(ipmiSelObject);
265 auto server = sdbusplus::asio::object_server(conn);
266
267 // Add SEL Interface
268 std::shared_ptr<sdbusplus::asio::dbus_interface> ifaceAddSel =
269 server.add_interface(ipmiSelPath, ipmiSelAddInterface);
270
271 // Add a new SEL entry
272 ifaceAddSel->register_method(
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700273 "IpmiSelAdd", [](const std::string& message, const std::string& path,
274 const std::vector<uint8_t>& selData,
275 const bool& assert, const uint16_t& genId) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700276 return selAddSystemRecord(message, path, selData, assert, genId);
277 });
278 // Add a new OEM SEL entry
279 ifaceAddSel->register_method(
280 "IpmiSelAddOem",
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700281 [](const std::string& message, const std::vector<uint8_t>& selData,
282 const uint8_t& recordType) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700283 return selAddOemRecord(message, selData, recordType);
284 });
Charles Boyer9f476e82021-07-29 16:33:01 -0500285
286#ifdef SEL_LOGGER_CLEARS_SEL
287#ifndef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
288 // Clear SEL entries
289 ifaceAddSel->register_method("Clear", []() { clearSelLogFiles(); });
290#endif
291#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700292 ifaceAddSel->initialize();
293
294#ifdef SEL_LOGGER_MONITOR_THRESHOLD_EVENTS
Patrick Williamsccef2272022-07-22 19:26:54 -0500295 sdbusplus::bus::match_t thresholdAssertMonitor =
Zhikui Ren25b26e12020-06-26 20:18:19 -0700296 startThresholdAssertMonitor(conn);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700297#endif
298
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800299#ifdef REDFISH_LOG_MONITOR_PULSE_EVENTS
Patrick Williamsccef2272022-07-22 19:26:54 -0500300 sdbusplus::bus::match_t pulseEventMonitor = startPulseEventMonitor(conn);
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800301#endif
302
Charles Hsudbd77b92020-10-29 11:20:34 +0800303#ifdef SEL_LOGGER_MONITOR_WATCHDOG_EVENTS
Patrick Williamsccef2272022-07-22 19:26:54 -0500304 sdbusplus::bus::match_t watchdogEventMonitor =
Charles Hsudbd77b92020-10-29 11:20:34 +0800305 startWatchdogEventMonitor(conn);
306#endif
George Hung486e42e2021-04-14 20:20:42 +0800307
308#ifdef SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
309 startThresholdAlarmMonitor(conn);
310#endif
JinFuLin7c2810b2022-12-02 13:55:28 +0800311
312#ifdef SEL_LOGGER_MONITOR_HOST_ERROR_EVENTS
313 startHostErrorEventMonitor(conn);
314#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700315 io.run();
316
317 return 0;
318}