1 #include "config.h"
2 
3 #include "elog_watch.hpp"
4 
5 #include "dump_internal.hpp"
6 #include "dump_serialize.hpp"
7 #include "errors_map.hpp"
8 #include "xyz/openbmc_project/Dump/Create/error.hpp"
9 
10 #include <cereal/cereal.hpp>
11 #include <phosphor-logging/elog.hpp>
12 #include <phosphor-logging/lg2.hpp>
13 #include <sdbusplus/exception.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 namespace phosphor::logging;
28 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging";
29 using Message = std::string;
30 using Attributes = std::variant<Message>;
31 using AttributeName = std::string;
32 using AttributeMap = std::map<AttributeName, Attributes>;
33 using PropertyName = std::string;
34 using PropertyMap = std::map<PropertyName, AttributeMap>;
35 
36 Watch::Watch(sdbusplus::bus_t& bus, IMgr& iMgr) :
37     iMgr(iMgr),
38     addMatch(bus,
39              sdbusplus::bus::match::rules::interfacesAdded() +
40                  sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING),
41              std::bind(std::mem_fn(&Watch::addCallback), this,
42                        std::placeholders::_1)),
43     delMatch(bus,
44              sdbusplus::bus::match::rules::interfacesRemoved() +
45                  sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING),
46              std::bind(std::mem_fn(&Watch::delCallback), this,
47                        std::placeholders::_1))
48 {
49     std::filesystem::path file(ELOG_ID_PERSIST_PATH);
50     if (std::filesystem::exists(file))
51     {
52         if (!deserialize(ELOG_ID_PERSIST_PATH, elogList))
53         {
54             lg2::error("Error occurred during error id deserialize");
55         }
56     }
57 }
58 
59 void Watch::addCallback(sdbusplus::message_t& msg)
60 {
61     using QuotaExceeded =
62         sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded;
63 
64     sdbusplus::message::object_path objectPath;
65     PropertyMap propertyMap;
66     try
67     {
68         msg.read(objectPath, propertyMap);
69     }
70     catch (const sdbusplus::exception_t& e)
71     {
72         lg2::error("Failed to parse elog add signal, errormsg: {ERROR}, "
73                    "REPLY_SIG: {REPLY_SIG}",
74                    "ERROR", e, "REPLY_SIG", msg.get_signature());
75         return;
76     }
77 
78     std::size_t found = objectPath.str.find("entry");
79     if (found == std::string::npos)
80     {
81         // Not a new error entry skip
82         return;
83     }
84 
85     auto eId = getEid(objectPath);
86 
87     auto search = elogList.find(eId);
88     if (search != elogList.end())
89     {
90         // elog exists in the list, Skip the dump
91         return;
92     }
93 
94     auto iter = propertyMap.find("xyz.openbmc_project.Logging.Entry");
95     if (iter == propertyMap.end())
96     {
97         return;
98     }
99 
100     auto attr = iter->second.find("Message");
101     if (attr == iter->second.end())
102     {
103         return;
104     }
105 
106     auto& data = std::get<PropertyName>(attr->second);
107     if (data.empty())
108     {
109         // No Message skip
110         return;
111     }
112 
113     EType errorType;
114     for (const auto& [type, errorList] : errorMap)
115     {
116         auto error = std::find(errorList.begin(), errorList.end(), data);
117         if (error != errorList.end())
118         {
119             errorType = type;
120             break;
121         }
122     }
123 
124     // error not supported in the configuration
125     if (errorType.empty())
126     {
127         return;
128     }
129 
130     std::vector<std::string> fullPaths;
131     fullPaths.push_back(objectPath);
132 
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 
141         auto item = std::find_if(phosphor::dump::bmc::TypeMap.begin(),
142                                  phosphor::dump::bmc::TypeMap.end(),
143                                  [errorType](const auto& err) {
144             return (err.second == errorType);
145         });
146         if (item != phosphor::dump::bmc::TypeMap.end())
147         {
148             iMgr.IMgr::create((*item).first, fullPaths);
149         }
150     }
151     catch (const QuotaExceeded& e)
152     {
153         // No action now
154     }
155     return;
156 }
157 
158 void Watch::delCallback(sdbusplus::message_t& msg)
159 {
160     sdbusplus::message::object_path objectPath;
161     try
162     {
163         msg.read(objectPath);
164     }
165     catch (const sdbusplus::exception_t& e)
166     {
167         lg2::error("Failed to parse elog del signal, errormsg: {ERROR}, "
168                    "REPLY_SIG: {REPLY_SIG}",
169                    "ERROR", e, "REPLY_SIG", msg.get_signature());
170         return;
171     }
172 
173     std::size_t found = objectPath.str.find("entry");
174     if (found == std::string::npos)
175     {
176         // Not a error entry so skip
177         return;
178     }
179 
180     // Get elog id
181     auto eId = getEid(objectPath);
182 
183     // Delete the elog entry from the list and serialize
184     auto search = elogList.find(eId);
185     if (search != elogList.end())
186     {
187         elogList.erase(search);
188         phosphor::dump::elog::serialize(elogList);
189     }
190 }
191 
192 } // namespace elog
193 } // namespace dump
194 } // namespace phosphor
195