blob: 5f330e09f90a4efa11132277eb8f1443b8048361 [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
33struct DBusInternalError final : public sdbusplus::exception_t
34{
Zhikui Ren672bdfc2020-07-14 11:37:01 -070035 const char* name() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070036 {
37 return "org.freedesktop.DBus.Error.Failed";
38 };
Zhikui Ren672bdfc2020-07-14 11:37:01 -070039 const char* description() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070040 {
41 return "internal error";
42 };
Zhikui Ren672bdfc2020-07-14 11:37:01 -070043 const char* what() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070044 {
45 return "org.freedesktop.DBus.Error.Failed: "
46 "internal error";
47 };
48};
49
Zhikui Ren672bdfc2020-07-14 11:37:01 -070050static bool getSELLogFiles(std::vector<std::filesystem::path>& selLogFiles)
Jason M. Billsc4a336f2019-04-23 10:43:10 -070051{
52 // Loop through the directory looking for ipmi_sel log files
Zhikui Ren672bdfc2020-07-14 11:37:01 -070053 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Billsc4a336f2019-04-23 10:43:10 -070054 std::filesystem::directory_iterator(selLogDir))
55 {
56 std::string filename = dirEnt.path().filename();
57 if (boost::starts_with(filename, selLogFilename))
58 {
59 // If we find an ipmi_sel log file, save the path
60 selLogFiles.emplace_back(selLogDir / filename);
61 }
62 }
63 // As the log files rotate, they are appended with a ".#" that is higher for
64 // the older logs. Since we don't expect more than 10 log files, we
65 // can just sort the list to get them in order from newest to oldest
66 std::sort(selLogFiles.begin(), selLogFiles.end());
67
68 return !selLogFiles.empty();
69}
70
Jason M. Bills5e049d32018-10-19 12:59:38 -070071static unsigned int initializeRecordId(void)
72{
Jason M. Billsc4a336f2019-04-23 10:43:10 -070073 std::vector<std::filesystem::path> selLogFiles;
74 if (!getSELLogFiles(selLogFiles))
Jason M. Bills5e049d32018-10-19 12:59:38 -070075 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -070076 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -070077 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -070078 std::ifstream logStream(selLogFiles.front());
79 if (!logStream.is_open())
Jason M. Bills5e049d32018-10-19 12:59:38 -070080 {
Jason M. Billsc4a336f2019-04-23 10:43:10 -070081 return selInvalidRecID;
82 }
83 std::string line;
84 std::string newestEntry;
85 while (std::getline(logStream, line))
86 {
87 newestEntry = line;
88 }
Jason M. Bills5e049d32018-10-19 12:59:38 -070089
Jason M. Billsc4a336f2019-04-23 10:43:10 -070090 std::vector<std::string> newestEntryFields;
91 boost::split(newestEntryFields, newestEntry, boost::is_any_of(" ,"),
92 boost::token_compress_on);
93 if (newestEntryFields.size() < 4)
94 {
95 return selInvalidRecID;
Jason M. Bills5e049d32018-10-19 12:59:38 -070096 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -070097
98 return std::stoul(newestEntryFields[1]);
Jason M. Bills5e049d32018-10-19 12:59:38 -070099}
100
101static unsigned int getNewRecordId(void)
102{
103 static unsigned int recordId = initializeRecordId();
104
Jason M. Bills6afe9562019-08-29 16:33:55 -0700105 // If the log has been cleared, also clear the current ID
106 std::vector<std::filesystem::path> selLogFiles;
107 if (!getSELLogFiles(selLogFiles))
108 {
109 recordId = selInvalidRecID;
110 }
111
Jason M. Bills5e049d32018-10-19 12:59:38 -0700112 if (++recordId >= selInvalidRecID)
113 {
114 recordId = 1;
115 }
116 return recordId;
117}
118
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700119static void toHexStr(const std::vector<uint8_t>& data, std::string& hexStr)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700120{
121 std::stringstream stream;
122 stream << std::hex << std::uppercase << std::setfill('0');
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700123 for (const int& v : data)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700124 {
125 stream << std::setw(2) << v;
126 }
127 hexStr = stream.str();
128}
129
Jason M. Bills97be3532018-11-02 13:09:16 -0700130template <typename... T>
131static uint16_t
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700132 selAddSystemRecord(const std::string& message, const std::string& path,
133 const std::vector<uint8_t>& selData, const bool& assert,
134 const uint16_t& genId, T&&... metadata)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700135{
136 // Only 3 bytes of SEL event data are allowed in a system record
137 if (selData.size() > selEvtDataMaxSize)
138 {
139 throw std::invalid_argument("Event data too large");
140 }
141 std::string selDataStr;
142 toHexStr(selData, selDataStr);
143
144 unsigned int recordId = getNewRecordId();
Jason M. Bills97be3532018-11-02 13:09:16 -0700145 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
146 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
147 recordId, "IPMI_SEL_RECORD_TYPE=%x", selSystemType,
148 "IPMI_SEL_GENERATOR_ID=%x", genId,
149 "IPMI_SEL_SENSOR_PATH=%s", path.c_str(),
150 "IPMI_SEL_EVENT_DIR=%x", assert, "IPMI_SEL_DATA=%s",
151 selDataStr.c_str(), std::forward<T>(metadata)..., NULL);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700152 return recordId;
153}
154
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700155static uint16_t selAddOemRecord(const std::string& message,
156 const std::vector<uint8_t>& selData,
157 const uint8_t& recordType)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700158{
159 // A maximum of 13 bytes of SEL event data are allowed in an OEM record
160 if (selData.size() > selOemDataMaxSize)
161 {
162 throw std::invalid_argument("Event data too large");
163 }
164 std::string selDataStr;
165 toHexStr(selData, selDataStr);
166
167 unsigned int recordId = getNewRecordId();
168 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
169 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
170 recordId, "IPMI_SEL_RECORD_TYPE=%x", recordType,
171 "IPMI_SEL_DATA=%s", selDataStr.c_str(), NULL);
172 return recordId;
173}
174
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700175int main(int argc, char* argv[])
Jason M. Bills5e049d32018-10-19 12:59:38 -0700176{
177 // setup connection to dbus
178 boost::asio::io_service io;
179 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
180
181 // IPMI SEL Object
182 conn->request_name(ipmiSelObject);
183 auto server = sdbusplus::asio::object_server(conn);
184
185 // Add SEL Interface
186 std::shared_ptr<sdbusplus::asio::dbus_interface> ifaceAddSel =
187 server.add_interface(ipmiSelPath, ipmiSelAddInterface);
188
189 // Add a new SEL entry
190 ifaceAddSel->register_method(
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700191 "IpmiSelAdd", [](const std::string& message, const std::string& path,
192 const std::vector<uint8_t>& selData,
193 const bool& assert, const uint16_t& genId) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700194 return selAddSystemRecord(message, path, selData, assert, genId);
195 });
196 // Add a new OEM SEL entry
197 ifaceAddSel->register_method(
198 "IpmiSelAddOem",
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700199 [](const std::string& message, const std::vector<uint8_t>& selData,
200 const uint8_t& recordType) {
Jason M. Bills5e049d32018-10-19 12:59:38 -0700201 return selAddOemRecord(message, selData, recordType);
202 });
203 ifaceAddSel->initialize();
204
205#ifdef SEL_LOGGER_MONITOR_THRESHOLD_EVENTS
Zhikui Ren25b26e12020-06-26 20:18:19 -0700206 sdbusplus::bus::match::match thresholdAssertMonitor =
207 startThresholdAssertMonitor(conn);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700208#endif
209
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800210#ifdef REDFISH_LOG_MONITOR_PULSE_EVENTS
211 sdbusplus::bus::match::match pulseEventMonitor =
212 startPulseEventMonitor(conn);
213#endif
214
Jason M. Bills5e049d32018-10-19 12:59:38 -0700215 io.run();
216
217 return 0;
218}