blob: 186072e14549828380844c6c0b1cf21b31f8fc51 [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>
Jason M. Bills5e049d32018-10-19 12:59:38 -070019#include <boost/container/flat_map.hpp>
20#include <boost/container/flat_set.hpp>
Zhikui Ren672bdfc2020-07-14 11:37:01 -070021#include <pulse_event_monitor.hpp>
22#include <sdbusplus/asio/object_server.hpp>
23#include <sel_logger.hpp>
24#include <threshold_event_monitor.hpp>
25
Jason M. Billsc4a336f2019-04-23 10:43:10 -070026#include <filesystem>
27#include <fstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070028#include <iomanip>
29#include <iostream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070030#include <sstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070031
32struct DBusInternalError final : public sdbusplus::exception_t
33{
Zhikui Ren672bdfc2020-07-14 11:37:01 -070034 const char* name() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070035 {
36 return "org.freedesktop.DBus.Error.Failed";
37 };
Zhikui Ren672bdfc2020-07-14 11:37:01 -070038 const char* description() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070039 {
40 return "internal error";
41 };
Zhikui Ren672bdfc2020-07-14 11:37:01 -070042 const char* what() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070043 {
44 return "org.freedesktop.DBus.Error.Failed: "
45 "internal error";
46 };
47};
48
Zhikui Ren672bdfc2020-07-14 11:37:01 -070049static bool getSELLogFiles(std::vector<std::filesystem::path>& selLogFiles)
Jason M. Billsc4a336f2019-04-23 10:43:10 -070050{
51 // Loop through the directory looking for ipmi_sel log files
Zhikui Ren672bdfc2020-07-14 11:37:01 -070052 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Billsc4a336f2019-04-23 10:43:10 -070053 std::filesystem::directory_iterator(selLogDir))
54 {
55 std::string filename = dirEnt.path().filename();
56 if (boost::starts_with(filename, selLogFilename))
57 {
58 // If we find an ipmi_sel log file, save the path
59 selLogFiles.emplace_back(selLogDir / filename);
60 }
61 }
62 // As the log files rotate, they are appended with a ".#" that is higher for
63 // the older logs. Since we don't expect more than 10 log files, we
64 // can just sort the list to get them in order from newest to oldest
65 std::sort(selLogFiles.begin(), selLogFiles.end());
66
67 return !selLogFiles.empty();
68}
69
Jason M. Bills5e049d32018-10-19 12:59:38 -070070static unsigned int initializeRecordId(void)
71{
Jason M. Billsc4a336f2019-04-23 10:43:10 -070072 std::vector<std::filesystem::path> selLogFiles;
73 if (!getSELLogFiles(selLogFiles))
Jason M. Bills5e049d32018-10-19 12:59:38 -070074 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -070075 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -070076 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -070077 std::ifstream logStream(selLogFiles.front());
78 if (!logStream.is_open())
Jason M. Bills5e049d32018-10-19 12:59:38 -070079 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -070080 return selInvalidRecID;
81 }
82 std::string line;
83 std::string newestEntry;
84 while (std::getline(logStream, line))
85 {
86 newestEntry = line;
87 }
Jason M. Bills5e049d32018-10-19 12:59:38 -070088
Jason M. Billsc4a336f2019-04-23 10:43:10 -070089 std::vector<std::string> newestEntryFields;
90 boost::split(newestEntryFields, newestEntry, boost::is_any_of(" ,"),
91 boost::token_compress_on);
92 if (newestEntryFields.size() < 4)
93 {
94 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -070095 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -070096
97 return std::stoul(newestEntryFields[1]);
Jason M. Bills5e049d32018-10-19 12:59:38 -070098}
99
100static unsigned int getNewRecordId(void)
101{
102 static unsigned int recordId = initializeRecordId();
103
Jason M. Bills6afe9562019-08-29 16:33:55 -0700104 // If the log has been cleared, also clear the current ID
105 std::vector<std::filesystem::path> selLogFiles;
106 if (!getSELLogFiles(selLogFiles))
107 {
108 recordId = selInvalidRecID;
109 }
110
Jason M. Bills5e049d32018-10-19 12:59:38 -0700111 if (++recordId >= selInvalidRecID)
112 {
113 recordId = 1;
114 }
115 return recordId;
116}
117
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700118static void toHexStr(const std::vector<uint8_t>& data, std::string& hexStr)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700119{
120 std::stringstream stream;
121 stream << std::hex << std::uppercase << std::setfill('0');
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700122 for (const int& v : data)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700123 {
124 stream << std::setw(2) << v;
125 }
126 hexStr = stream.str();
127}
128
Jason M. Bills97be3532018-11-02 13:09:16 -0700129template <typename... T>
130static uint16_t
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700131 selAddSystemRecord(const std::string& message, const std::string& path,
132 const std::vector<uint8_t>& selData, const bool& assert,
133 const uint16_t& genId, T&&... metadata)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700134{
135 // Only 3 bytes of SEL event data are allowed in a system record
136 if (selData.size() > selEvtDataMaxSize)
137 {
138 throw std::invalid_argument("Event data too large");
139 }
140 std::string selDataStr;
141 toHexStr(selData, selDataStr);
142
143 unsigned int recordId = getNewRecordId();
Jason M. Bills97be3532018-11-02 13:09:16 -0700144 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
145 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
146 recordId, "IPMI_SEL_RECORD_TYPE=%x", selSystemType,
147 "IPMI_SEL_GENERATOR_ID=%x", genId,
148 "IPMI_SEL_SENSOR_PATH=%s", path.c_str(),
149 "IPMI_SEL_EVENT_DIR=%x", assert, "IPMI_SEL_DATA=%s",
150 selDataStr.c_str(), std::forward<T>(metadata)..., NULL);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700151 return recordId;
152}
153
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700154static uint16_t selAddOemRecord(const std::string& message,
155 const std::vector<uint8_t>& selData,
156 const uint8_t& recordType)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700157{
158 // A maximum of 13 bytes of SEL event data are allowed in an OEM record
159 if (selData.size() > selOemDataMaxSize)
160 {
161 throw std::invalid_argument("Event data too large");
162 }
163 std::string selDataStr;
164 toHexStr(selData, selDataStr);
165
166 unsigned int recordId = getNewRecordId();
167 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
168 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
169 recordId, "IPMI_SEL_RECORD_TYPE=%x", recordType,
170 "IPMI_SEL_DATA=%s", selDataStr.c_str(), NULL);
171 return recordId;
172}
173
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700174int main(int argc, char* argv[])
Jason M. Bills5e049d32018-10-19 12:59:38 -0700175{
176 // setup connection to dbus
177 boost::asio::io_service io;
178 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
179
180 // IPMI SEL Object
181 conn->request_name(ipmiSelObject);
182 auto server = sdbusplus::asio::object_server(conn);
183
184 // Add SEL Interface
185 std::shared_ptr<sdbusplus::asio::dbus_interface> ifaceAddSel =
186 server.add_interface(ipmiSelPath, ipmiSelAddInterface);
187
188 // Add a new SEL entry
189 ifaceAddSel->register_method(
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700190 "IpmiSelAdd", [](const std::string& message, const std::string& path,
191 const std::vector<uint8_t>& selData,
192 const bool& assert, const uint16_t& genId) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700193 return selAddSystemRecord(message, path, selData, assert, genId);
194 });
195 // Add a new OEM SEL entry
196 ifaceAddSel->register_method(
197 "IpmiSelAddOem",
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700198 [](const std::string& message, const std::vector<uint8_t>& selData,
199 const uint8_t& recordType) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700200 return selAddOemRecord(message, selData, recordType);
201 });
202 ifaceAddSel->initialize();
203
204#ifdef SEL_LOGGER_MONITOR_THRESHOLD_EVENTS
Zhikui Ren25b26e12020-06-26 20:18:19 -0700205 sdbusplus::bus::match::match thresholdAssertMonitor =
206 startThresholdAssertMonitor(conn);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700207#endif
208
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800209#ifdef REDFISH_LOG_MONITOR_PULSE_EVENTS
210 sdbusplus::bus::match::match pulseEventMonitor =
211 startPulseEventMonitor(conn);
212#endif
213
Jason M. Bills5e049d32018-10-19 12:59:38 -0700214 io.run();
215
216 return 0;
217}