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