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