1 #include <cereal/cereal.hpp>
2 #include <phosphor-logging/elog.hpp>
3 
4 #include "elog_watch.hpp"
5 #include "dump_internal.hpp"
6 #include "xyz/openbmc_project/Dump/Create/error.hpp"
7 #include "dump_serialize.hpp"
8 #include "config.h"
9 
10 // Register class version with Cereal
11 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION);
12 
13 namespace phosphor
14 {
15 namespace dump
16 {
17 namespace elog
18 {
19 
20 using namespace phosphor::logging;
21 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging";
22 constexpr auto INTERNAL_FAILURE =
23     "xyz.openbmc_project.Common.Error.InternalFailure";
24 using Message = std::string;
25 using Attributes = sdbusplus::message::variant<Message>;
26 using AttributeName = std::string;
27 using AttributeMap = std::map<AttributeName, Attributes>;
28 using PropertyName = std::string;
29 using PropertyMap = std::map<PropertyName, AttributeMap>;
30 using LogEntryMsg = std::pair<sdbusplus::message::object_path, PropertyMap>;
31 
32 Watch::Watch(sdbusplus::bus::bus& bus, IMgr& iMgr):
33     iMgr(iMgr),
34     addMatch(
35         bus,
36         sdbusplus::bus::match::rules::interfacesAdded() +
37         sdbusplus::bus::match::rules::path_namespace(
38             OBJ_LOGGING),
39         std::bind(std::mem_fn(&Watch::addCallback),
40                   this, std::placeholders::_1)),
41     delMatch(
42         bus,
43         sdbusplus::bus::match::rules::interfacesRemoved() +
44         sdbusplus::bus::match::rules::path_namespace(
45             OBJ_LOGGING),
46         std::bind(std::mem_fn(&Watch::delCallback),
47                   this, std::placeholders::_1))
48 {
49 
50     fs::path file(ELOG_ID_PERSIST_PATH);
51     if (fs::exists(file))
52     {
53         if (!deserialize(ELOG_ID_PERSIST_PATH, elogList))
54         {
55             log<level::ERR>("Error occurred during error id deserialize");
56         }
57     }
58 }
59 
60 void Watch::addCallback(sdbusplus::message::message& msg)
61 {
62     using Type =
63         sdbusplus::xyz::openbmc_project::Dump::Internal::server::Create::Type;
64     using QuotaExceeded =
65         sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded;
66 
67     LogEntryMsg logEntry;
68     msg.read(logEntry);
69 
70     std::string objectPath(std::move(logEntry.first));
71 
72     std::size_t found = objectPath.find("entry");
73     if (found == std::string::npos)
74     {
75         //Not a new error entry skip
76         return;
77     }
78 
79     auto eId = getEid(objectPath);
80 
81     auto search = elogList.find(eId);
82     if (search != elogList.end())
83     {
84         //elog exists in the list, Skip the dump
85         return;
86     }
87 
88     auto iter = logEntry.second.find("xyz.openbmc_project.Logging.Entry");
89     if (iter == logEntry.second.end())
90     {
91         return;
92     }
93 
94     auto attr = iter->second.find("Message");
95     if (attr == iter->second.end())
96     {
97         return;
98     }
99 
100     auto& data =
101         sdbusplus::message::variant_ns::get<PropertyName>(attr->second);
102     if (data.empty())
103     {
104         //No Message skip
105         return;
106     }
107 
108     if (data != INTERNAL_FAILURE)
109     {
110         //Not a InternalFailure, skip
111         return;
112     }
113 
114     std::vector<std::string> fullPaths;
115     fullPaths.push_back(objectPath);
116 
117     try
118     {
119         //Save the elog information. This is to avoid dump requests
120         //in elog restore path.
121         elogList.insert(eId);
122 
123         phosphor::dump::elog::serialize(elogList);
124 
125         //Call internal create function to initiate dump
126         iMgr.IMgr::create(Type::InternalFailure, fullPaths);
127     }
128     catch (QuotaExceeded& e)
129     {
130         //No action now
131     }
132     return;
133 }
134 
135 void Watch::delCallback(sdbusplus::message::message& msg)
136 {
137     sdbusplus::message::object_path logEntry;
138     msg.read(logEntry);
139 
140     //Get elog entry message string.
141     std::string objectPath(logEntry);
142 
143     //Get elog id
144     auto eId = getEid(objectPath);
145 
146     //Delete the elog entry from the list and serialize
147     auto search = elogList.find(eId);
148     if (search != elogList.end())
149     {
150         elogList.erase(search);
151         phosphor::dump::elog::serialize(elogList);
152     }
153 }
154 
155 }//namespace elog
156 }//namespace dump
157 }//namespace phosphor
158