blob: 6068e20ac61aceb2ca4be795eb769e980347ca16 [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
18#include <boost/container/flat_map.hpp>
19#include <boost/container/flat_set.hpp>
20#include <experimental/string_view>
21#include <iomanip>
22#include <iostream>
Nikhil Potadeafbaa092019-03-06 16:18:13 -080023#include <pulse_event_monitor.hpp>
Jason M. Bills5e049d32018-10-19 12:59:38 -070024#include <sdbusplus/asio/object_server.hpp>
25#include <sel_logger.hpp>
26#include <sstream>
27#include <threshold_event_monitor.hpp>
28
29struct DBusInternalError final : public sdbusplus::exception_t
30{
31 const char *name() const noexcept override
32 {
33 return "org.freedesktop.DBus.Error.Failed";
34 };
35 const char *description() const noexcept override
36 {
37 return "internal error";
38 };
39 const char *what() const noexcept override
40 {
41 return "org.freedesktop.DBus.Error.Failed: "
42 "internal error";
43 };
44};
45
46static unsigned int initializeRecordId(void)
47{
48 int journalError = -1;
49 sd_journal *journal;
50 journalError = sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY);
51 if (journalError < 0)
52 {
53 std::cerr << "Failed to open journal: " << strerror(-journalError)
54 << "\n";
55 throw DBusInternalError();
56 }
57 unsigned int recordId = selInvalidRecID;
58 char match[256] = {};
59 snprintf(match, sizeof(match), "MESSAGE_ID=%s", selMessageId);
60 sd_journal_add_match(journal, match, 0);
61 SD_JOURNAL_FOREACH_BACKWARDS(journal)
62 {
63 const char *data = nullptr;
64 size_t length;
65
66 journalError = sd_journal_get_data(journal, "IPMI_SEL_RECORD_ID",
67 (const void **)&data, &length);
68 if (journalError < 0)
69 {
70 std::cerr << "Failed to read IPMI_SEL_RECORD_ID field: "
71 << strerror(-journalError) << "\n";
72 continue;
73 }
74 if (journalError =
75 sscanf(data, "IPMI_SEL_RECORD_ID=%u", &recordId) != 1)
76 {
77 std::cerr << "Failed to parse record ID: " << journalError << "\n";
78 throw DBusInternalError();
79 }
80 break;
81 }
82 sd_journal_close(journal);
83 return recordId;
84}
85
86static unsigned int getNewRecordId(void)
87{
88 static unsigned int recordId = initializeRecordId();
89
90 if (++recordId >= selInvalidRecID)
91 {
92 recordId = 1;
93 }
94 return recordId;
95}
96
97static void toHexStr(const std::vector<uint8_t> &data, std::string &hexStr)
98{
99 std::stringstream stream;
100 stream << std::hex << std::uppercase << std::setfill('0');
101 for (const int &v : data)
102 {
103 stream << std::setw(2) << v;
104 }
105 hexStr = stream.str();
106}
107
Jason M. Bills97be3532018-11-02 13:09:16 -0700108template <typename... T>
109static uint16_t
110 selAddSystemRecord(const std::string &message, const std::string &path,
111 const std::vector<uint8_t> &selData, const bool &assert,
112 const uint16_t &genId, T &&... metadata)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700113{
114 // Only 3 bytes of SEL event data are allowed in a system record
115 if (selData.size() > selEvtDataMaxSize)
116 {
117 throw std::invalid_argument("Event data too large");
118 }
119 std::string selDataStr;
120 toHexStr(selData, selDataStr);
121
122 unsigned int recordId = getNewRecordId();
Jason M. Bills97be3532018-11-02 13:09:16 -0700123 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
124 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
125 recordId, "IPMI_SEL_RECORD_TYPE=%x", selSystemType,
126 "IPMI_SEL_GENERATOR_ID=%x", genId,
127 "IPMI_SEL_SENSOR_PATH=%s", path.c_str(),
128 "IPMI_SEL_EVENT_DIR=%x", assert, "IPMI_SEL_DATA=%s",
129 selDataStr.c_str(), std::forward<T>(metadata)..., NULL);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700130 return recordId;
131}
132
133static uint16_t selAddOemRecord(const std::string &message,
134 const std::vector<uint8_t> &selData,
135 const uint8_t &recordType)
136{
137 // A maximum of 13 bytes of SEL event data are allowed in an OEM record
138 if (selData.size() > selOemDataMaxSize)
139 {
140 throw std::invalid_argument("Event data too large");
141 }
142 std::string selDataStr;
143 toHexStr(selData, selDataStr);
144
145 unsigned int recordId = getNewRecordId();
146 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", selPriority,
147 "MESSAGE_ID=%s", selMessageId, "IPMI_SEL_RECORD_ID=%d",
148 recordId, "IPMI_SEL_RECORD_TYPE=%x", recordType,
149 "IPMI_SEL_DATA=%s", selDataStr.c_str(), NULL);
150 return recordId;
151}
152
153int main(int argc, char *argv[])
154{
155 // setup connection to dbus
156 boost::asio::io_service io;
157 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
158
159 // IPMI SEL Object
160 conn->request_name(ipmiSelObject);
161 auto server = sdbusplus::asio::object_server(conn);
162
163 // Add SEL Interface
164 std::shared_ptr<sdbusplus::asio::dbus_interface> ifaceAddSel =
165 server.add_interface(ipmiSelPath, ipmiSelAddInterface);
166
167 // Add a new SEL entry
168 ifaceAddSel->register_method(
169 "IpmiSelAdd", [](const std::string &message, const std::string &path,
170 const std::vector<uint8_t> &selData,
171 const bool &assert, const uint16_t &genId) {
172 return selAddSystemRecord(message, path, selData, assert, genId);
173 });
174 // Add a new OEM SEL entry
175 ifaceAddSel->register_method(
176 "IpmiSelAddOem",
177 [](const std::string &message, const std::vector<uint8_t> &selData,
178 const uint8_t &recordType) {
179 return selAddOemRecord(message, selData, recordType);
180 });
181 ifaceAddSel->initialize();
182
183#ifdef SEL_LOGGER_MONITOR_THRESHOLD_EVENTS
184 sdbusplus::bus::match::match thresholdEventMonitor =
185 startThresholdEventMonitor(conn);
186#endif
187
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800188#ifdef REDFISH_LOG_MONITOR_PULSE_EVENTS
189 sdbusplus::bus::match::match pulseEventMonitor =
190 startPulseEventMonitor(conn);
191#endif
192
Jason M. Bills5e049d32018-10-19 12:59:38 -0700193 io.run();
194
195 return 0;
196}