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 <sdbusplus/exception.hpp> 13 14 #include <fstream> 15 16 // Register class version with Cereal 17 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION) 18 19 namespace phosphor 20 { 21 namespace dump 22 { 23 namespace elog 24 { 25 26 using namespace phosphor::logging; 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::bus& bus, IMgr& iMgr) : 36 iMgr(iMgr), 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 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 log<level::ERR>("Error occurred during error id deserialize"); 55 } 56 } 57 } 58 59 void Watch::addCallback(sdbusplus::message::message& 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::SdBusError& e) 71 { 72 log<level::ERR>("Failed to parse elog add signal", 73 entry("ERROR=%s", e.what()), 74 entry("REPLY_SIG=%s", 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( 142 phosphor::dump::bmc::TypeMap.begin(), 143 phosphor::dump::bmc::TypeMap.end(), 144 [errorType](const auto& err) { return (err.second == errorType); }); 145 if (item != phosphor::dump::bmc::TypeMap.end()) 146 { 147 iMgr.IMgr::create((*item).first, fullPaths); 148 } 149 } 150 catch (QuotaExceeded& e) 151 { 152 // No action now 153 } 154 return; 155 } 156 157 void Watch::delCallback(sdbusplus::message::message& msg) 158 { 159 sdbusplus::message::object_path objectPath; 160 try 161 { 162 msg.read(objectPath); 163 } 164 catch (const sdbusplus::exception::SdBusError& e) 165 { 166 log<level::ERR>("Failed to parse elog del signal", 167 entry("ERROR=%s", e.what()), 168 entry("REPLY_SIG=%s", msg.get_signature())); 169 return; 170 } 171 172 std::size_t found = objectPath.str.find("entry"); 173 if (found == std::string::npos) 174 { 175 // Not a error entry so skip 176 return; 177 } 178 179 // Get elog id 180 auto eId = getEid(objectPath); 181 182 // Delete the elog entry from the list and serialize 183 auto search = elogList.find(eId); 184 if (search != elogList.end()) 185 { 186 elogList.erase(search); 187 phosphor::dump::elog::serialize(elogList); 188 } 189 } 190 191 } // namespace elog 192 } // namespace dump 193 } // namespace phosphor 194