#include "config.h" #include "elog_watch.hpp" #include "dump_internal.hpp" #include "dump_serialize.hpp" #include "dump_types.hpp" #include "xyz/openbmc_project/Dump/Create/error.hpp" #include #include #include #include #include // Register class version with Cereal CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION) namespace phosphor { namespace dump { namespace elog { constexpr auto LOG_PATH = "/xyz/openbmc_project/logging"; using Message = std::string; using Attributes = std::variant; using AttributeName = std::string; using AttributeMap = std::map; using PropertyName = std::string; using PropertyMap = std::map; Watch::Watch(sdbusplus::bus_t& bus, Mgr& mgr) : mgr(mgr), addMatch(bus, sdbusplus::bus::match::rules::interfacesAdded() + sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING), std::bind(std::mem_fn(&Watch::addCallback), this, std::placeholders::_1)), delMatch(bus, sdbusplus::bus::match::rules::interfacesRemoved() + sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING), std::bind(std::mem_fn(&Watch::delCallback), this, std::placeholders::_1)) { std::filesystem::path file(ELOG_ID_PERSIST_PATH); if (std::filesystem::exists(file)) { if (!deserialize(ELOG_ID_PERSIST_PATH, elogList)) { lg2::error("Error occurred during error id deserialize"); } } } void Watch::addCallback(sdbusplus::message_t& msg) { using QuotaExceeded = sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded; sdbusplus::message::object_path objectPath; PropertyMap propertyMap; try { msg.read(objectPath, propertyMap); } catch (const sdbusplus::exception_t& e) { lg2::error("Failed to parse elog add signal, errormsg: {ERROR}, " "REPLY_SIG: {REPLY_SIG}", "ERROR", e, "REPLY_SIG", msg.get_signature()); return; } std::size_t found = objectPath.str.find("entry"); if (found == std::string::npos) { // Not a new error entry skip return; } auto eId = getEid(objectPath); auto search = elogList.find(eId); if (search != elogList.end()) { // elog exists in the list, Skip the dump return; } auto iter = propertyMap.find("xyz.openbmc_project.Logging.Entry"); if (iter == propertyMap.end()) { return; } auto attr = iter->second.find("Message"); if (attr == iter->second.end()) { return; } auto& data = std::get(attr->second); if (data.empty()) { // No Message skip return; } auto etype = findErrorType(data); if (!etype.has_value()) { // error not supported in the configuration return; } auto errorType = etype.value(); DumpCreateParams params; using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create; using CreateParameters = sdbusplus::common::xyz::openbmc_project::dump::Create::CreateParameters; using DumpType = sdbusplus::common::xyz::openbmc_project::dump::Create::DumpType; params[DumpIntr::convertCreateParametersToString( CreateParameters::FilePath)] = objectPath; params[DumpIntr::convertCreateParametersToString( CreateParameters::DumpType)] = DumpIntr::convertDumpTypeToString(DumpType::ErrorLog); params[DumpIntr::convertCreateParametersToString( CreateParameters::ErrorType)] = errorType; try { // Save the elog information. This is to avoid dump requests // in elog restore path. elogList.insert(eId); phosphor::dump::elog::serialize(elogList); mgr.Mgr::createDump(params); } catch (const QuotaExceeded& e) { // No action now } return; } void Watch::delCallback(sdbusplus::message_t& msg) { sdbusplus::message::object_path objectPath; try { msg.read(objectPath); } catch (const sdbusplus::exception_t& e) { lg2::error("Failed to parse elog del signal, errormsg: {ERROR}, " "REPLY_SIG: {REPLY_SIG}", "ERROR", e, "REPLY_SIG", msg.get_signature()); return; } std::size_t found = objectPath.str.find("entry"); if (found == std::string::npos) { // Not a error entry so skip return; } // Get elog id auto eId = getEid(objectPath); // Delete the elog entry from the list and serialize auto search = elogList.find(eId); if (search != elogList.end()) { elogList.erase(search); phosphor::dump::elog::serialize(elogList); } } } // namespace elog } // namespace dump } // namespace phosphor