1 #include "config.h"
2 
3 #include "elog_watch.hpp"
4 
5 #include "dump_internal.hpp"
6 #include "dump_serialize.hpp"
7 #include "dump_types.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 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 
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 
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 
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