1 #include "config.h"
2
3 #include "elog_watch.hpp"
4
5 #include "dump_serialize.hpp"
6 #include "dump_types.hpp"
7 #include "xyz/openbmc_project/Dump/Create/error.hpp"
8
9 #include <cereal/cereal.hpp>
10 #include <phosphor-logging/elog.hpp>
11 #include <phosphor-logging/lg2.hpp>
12 #include <sdbusplus/exception.hpp>
13 #include <xyz/openbmc_project/Dump/Create/common.hpp>
14
15 #include <fstream>
16
17 // Register class version with Cereal
18 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION)
19
20 namespace phosphor
21 {
22 namespace dump
23 {
24 namespace elog
25 {
26
27 using Message = std::string;
28 using Attributes = std::variant<Message>;
29 using AttributeName = std::string;
30 using AttributeMap = std::map<AttributeName, Attributes>;
31 using PropertyName = std::string;
32 using PropertyMap = std::map<PropertyName, AttributeMap>;
33
Watch(sdbusplus::bus_t & bus,Mgr & mgr)34 Watch::Watch(sdbusplus::bus_t& bus, Mgr& mgr) :
35 mgr(mgr),
36 addMatch(bus,
37 sdbusplus::bus::match::rules::interfacesAdded() +
38 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING),
39 std::bind(std::mem_fn(&Watch::addCallback), this,
40 std::placeholders::_1)),
41 delMatch(bus,
42 sdbusplus::bus::match::rules::interfacesRemoved() +
43 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING),
44 std::bind(std::mem_fn(&Watch::delCallback), this,
45 std::placeholders::_1))
46 {
47 std::filesystem::path file(ELOG_ID_PERSIST_PATH);
48 if (std::filesystem::exists(file))
49 {
50 if (!deserialize(ELOG_ID_PERSIST_PATH, elogList))
51 {
52 lg2::error("Error occurred during error id deserialize");
53 }
54 }
55 }
56
addCallback(sdbusplus::message_t & msg)57 void Watch::addCallback(sdbusplus::message_t& msg)
58 {
59 using QuotaExceeded =
60 sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded;
61
62 sdbusplus::message::object_path objectPath;
63 PropertyMap propertyMap;
64 try
65 {
66 msg.read(objectPath, propertyMap);
67 }
68 catch (const sdbusplus::exception_t& e)
69 {
70 lg2::error("Failed to parse elog add signal, errormsg: {ERROR}, "
71 "REPLY_SIG: {REPLY_SIG}",
72 "ERROR", e, "REPLY_SIG", msg.get_signature());
73 return;
74 }
75
76 std::size_t found = objectPath.str.find("entry");
77 if (found == std::string::npos)
78 {
79 // Not a new error entry skip
80 return;
81 }
82
83 auto eId = getEid(objectPath);
84
85 auto search = elogList.find(eId);
86 if (search != elogList.end())
87 {
88 // elog exists in the list, Skip the dump
89 return;
90 }
91
92 auto iter = propertyMap.find("xyz.openbmc_project.Logging.Entry");
93 if (iter == propertyMap.end())
94 {
95 return;
96 }
97
98 auto attr = iter->second.find("Message");
99 if (attr == iter->second.end())
100 {
101 return;
102 }
103
104 auto& data = std::get<PropertyName>(attr->second);
105 if (data.empty())
106 {
107 // No Message skip
108 return;
109 }
110
111 auto etype = findErrorType(data);
112 if (!etype.has_value())
113 {
114 // error not supported in the configuration
115 return;
116 }
117
118 auto errorType = etype.value();
119
120 DumpCreateParams params;
121 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create;
122 using CreateParameters =
123 sdbusplus::common::xyz::openbmc_project::dump::Create::CreateParameters;
124 using DumpType =
125 sdbusplus::common::xyz::openbmc_project::dump::Create::DumpType;
126 params[DumpIntr::convertCreateParametersToString(
127 CreateParameters::FilePath)] = objectPath;
128 params[DumpIntr::convertCreateParametersToString(
129 CreateParameters::DumpType)] =
130 DumpIntr::convertDumpTypeToString(DumpType::ErrorLog);
131 params[DumpIntr::convertCreateParametersToString(
132 CreateParameters::ErrorType)] = errorType;
133 try
134 {
135 // Save the elog information. This is to avoid dump requests
136 // in elog restore path.
137 elogList.insert(eId);
138
139 phosphor::dump::elog::serialize(elogList);
140 mgr.Mgr::createDump(params);
141 }
142 catch (const QuotaExceeded& e)
143 {
144 // No action needed
145 lg2::warning("Skipping exception: QuotaExceeded during createDump");
146 }
147 return;
148 }
149
delCallback(sdbusplus::message_t & msg)150 void Watch::delCallback(sdbusplus::message_t& msg)
151 {
152 sdbusplus::message::object_path objectPath;
153 try
154 {
155 msg.read(objectPath);
156 }
157 catch (const sdbusplus::exception_t& e)
158 {
159 lg2::error("Failed to parse elog del signal, errormsg: {ERROR}, "
160 "REPLY_SIG: {REPLY_SIG}",
161 "ERROR", e, "REPLY_SIG", msg.get_signature());
162 return;
163 }
164
165 std::size_t found = objectPath.str.find("entry");
166 if (found == std::string::npos)
167 {
168 // Not a error entry so skip
169 return;
170 }
171
172 // Get elog id
173 auto eId = getEid(objectPath);
174
175 // Delete the elog entry from the list and serialize
176 auto search = elogList.find(eId);
177 if (search != elogList.end())
178 {
179 elogList.erase(search);
180 phosphor::dump::elog::serialize(elogList);
181 }
182 }
183
184 } // namespace elog
185 } // namespace dump
186 } // namespace phosphor
187