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 <fstream> 12 #include <phosphor-logging/elog.hpp> 13 #include <sdbusplus/exception.hpp> 14 15 // Register class version with Cereal 16 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION) 17 18 namespace phosphor 19 { 20 namespace dump 21 { 22 namespace elog 23 { 24 25 using namespace phosphor::logging; 26 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging"; 27 using Message = std::string; 28 using Attributes = std::variant<Message>; 29 using AttributeName = std::string; 30 using AttributeMap = std::map<AttributeName, Attributes>; 31 using PropertyName = std::string; 32 using PropertyMap = std::map<PropertyName, AttributeMap>; 33 34 Watch::Watch(sdbusplus::bus::bus& bus, IMgr& iMgr) : 35 iMgr(iMgr), 36 addMatch(bus, 37 sdbusplus::bus::match::rules::interfacesAdded() + 38 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING), 39 std::bind(std::mem_fn(&Watch::addCallback), this, 40 std::placeholders::_1)), 41 delMatch(bus, 42 sdbusplus::bus::match::rules::interfacesRemoved() + 43 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING), 44 std::bind(std::mem_fn(&Watch::delCallback), this, 45 std::placeholders::_1)) 46 { 47 48 fs::path file(ELOG_ID_PERSIST_PATH); 49 if (fs::exists(file)) 50 { 51 if (!deserialize(ELOG_ID_PERSIST_PATH, elogList)) 52 { 53 log<level::ERR>("Error occurred during error id deserialize"); 54 } 55 } 56 } 57 58 void Watch::addCallback(sdbusplus::message::message& 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::SdBusError& e) 70 { 71 log<level::ERR>("Failed to parse elog add signal", 72 entry("ERROR=%s", e.what()), 73 entry("REPLY_SIG=%s", 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 EType errorType; 113 for (const auto& [type, errorList] : errorMap) 114 { 115 auto error = std::find(errorList.begin(), errorList.end(), data); 116 if (error != errorList.end()) 117 { 118 errorType = type; 119 break; 120 } 121 } 122 123 // error not supported in the configuration 124 if (errorType.empty()) 125 { 126 return; 127 } 128 129 std::vector<std::string> fullPaths; 130 fullPaths.push_back(objectPath); 131 132 try 133 { 134 // Save the elog information. This is to avoid dump requests 135 // in elog restore path. 136 elogList.insert(eId); 137 138 phosphor::dump::elog::serialize(elogList); 139 140 auto item = std::find_if( 141 TypeMap.begin(), TypeMap.end(), 142 [errorType](const auto& err) { return (err.second == errorType); }); 143 if (item != TypeMap.end()) 144 { 145 iMgr.IMgr::create((*item).first, fullPaths); 146 } 147 } 148 catch (QuotaExceeded& e) 149 { 150 // No action now 151 } 152 return; 153 } 154 155 void Watch::delCallback(sdbusplus::message::message& msg) 156 { 157 sdbusplus::message::object_path objectPath; 158 try 159 { 160 msg.read(objectPath); 161 } 162 catch (const sdbusplus::exception::SdBusError& e) 163 { 164 log<level::ERR>("Failed to parse elog del signal", 165 entry("ERROR=%s", e.what()), 166 entry("REPLY_SIG=%s", msg.get_signature())); 167 return; 168 } 169 170 std::size_t found = objectPath.str.find("entry"); 171 if (found == std::string::npos) 172 { 173 // Not a error entry so skip 174 return; 175 } 176 177 // Get elog id 178 auto eId = getEid(objectPath); 179 180 // Delete the elog entry from the list and serialize 181 auto search = elogList.find(eId); 182 if (search != elogList.end()) 183 { 184 elogList.erase(search); 185 phosphor::dump::elog::serialize(elogList); 186 } 187 } 188 189 } // namespace elog 190 } // namespace dump 191 } // namespace phosphor 192