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 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging";
28 using Message = std::string;
29 using Attributes = std::variant<Message>;
30 using AttributeName = std::string;
31 using AttributeMap = std::map<AttributeName, Attributes>;
32 using PropertyName = std::string;
33 using PropertyMap = std::map<PropertyName, AttributeMap>;
34
Watch(sdbusplus::bus_t & bus,Mgr & mgr)35 Watch::Watch(sdbusplus::bus_t& bus, Mgr& mgr) :
36 mgr(mgr),
37 addMatch(bus,
38 sdbusplus::bus::match::rules::interfacesAdded() +
39 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING),
40 std::bind(std::mem_fn(&Watch::addCallback), this,
41 std::placeholders::_1)),
42 delMatch(bus,
43 sdbusplus::bus::match::rules::interfacesRemoved() +
44 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING),
45 std::bind(std::mem_fn(&Watch::delCallback), this,
46 std::placeholders::_1))
47 {
48 std::filesystem::path file(ELOG_ID_PERSIST_PATH);
49 if (std::filesystem::exists(file))
50 {
51 if (!deserialize(ELOG_ID_PERSIST_PATH, elogList))
52 {
53 lg2::error("Error occurred during error id deserialize");
54 }
55 }
56 }
57
addCallback(sdbusplus::message_t & msg)58 void Watch::addCallback(sdbusplus::message_t& msg)
59 {
60 using QuotaExceeded =
61 sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded;
62
63 sdbusplus::message::object_path objectPath;
64 PropertyMap propertyMap;
65 try
66 {
67 msg.read(objectPath, propertyMap);
68 }
69 catch (const sdbusplus::exception_t& e)
70 {
71 lg2::error("Failed to parse elog add signal, errormsg: {ERROR}, "
72 "REPLY_SIG: {REPLY_SIG}",
73 "ERROR", e, "REPLY_SIG", msg.get_signature());
74 return;
75 }
76
77 std::size_t found = objectPath.str.find("entry");
78 if (found == std::string::npos)
79 {
80 // Not a new error entry skip
81 return;
82 }
83
84 auto eId = getEid(objectPath);
85
86 auto search = elogList.find(eId);
87 if (search != elogList.end())
88 {
89 // elog exists in the list, Skip the dump
90 return;
91 }
92
93 auto iter = propertyMap.find("xyz.openbmc_project.Logging.Entry");
94 if (iter == propertyMap.end())
95 {
96 return;
97 }
98
99 auto attr = iter->second.find("Message");
100 if (attr == iter->second.end())
101 {
102 return;
103 }
104
105 auto& data = std::get<PropertyName>(attr->second);
106 if (data.empty())
107 {
108 // No Message skip
109 return;
110 }
111
112 auto etype = findErrorType(data);
113 if (!etype.has_value())
114 {
115 // error not supported in the configuration
116 return;
117 }
118
119 auto errorType = etype.value();
120
121 DumpCreateParams params;
122 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create;
123 using CreateParameters =
124 sdbusplus::common::xyz::openbmc_project::dump::Create::CreateParameters;
125 using DumpType =
126 sdbusplus::common::xyz::openbmc_project::dump::Create::DumpType;
127 params[DumpIntr::convertCreateParametersToString(
128 CreateParameters::FilePath)] = objectPath;
129 params[DumpIntr::convertCreateParametersToString(
130 CreateParameters::DumpType)] =
131 DumpIntr::convertDumpTypeToString(DumpType::ErrorLog);
132 params[DumpIntr::convertCreateParametersToString(
133 CreateParameters::ErrorType)] = errorType;
134 try
135 {
136 // Save the elog information. This is to avoid dump requests
137 // in elog restore path.
138 elogList.insert(eId);
139
140 phosphor::dump::elog::serialize(elogList);
141 mgr.Mgr::createDump(params);
142 }
143 catch (const QuotaExceeded& e)
144 {
145 // No action now
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