#include #include #include #include #include #include namespace watchdog { namespace dump { /** * @brief Callback for dump request properties change signal monitor * * @param msg - dbus message from the dbus match infrastructure * @param path - the object path we are monitoring * @param progressStatus - dump progress status * @return Always non-zero indicating no error, no cascading callbacks */ uint dumpStatusChanged(sdbusplus::message_t& msg, std::string path, DumpProgressStatus& progressStatus) { // reply (msg) will be a property change message std::string interface; std::map> property; msg.read(interface, property); // looking for property Status changes std::string propertyType = "Status"; auto dumpStatus = property.find(propertyType); if (dumpStatus != property.end()) { const std::string* status = std::get_if(&(dumpStatus->second)); if ((nullptr != status) && ("xyz.openbmc_project.Common.Progress." "OperationStatus.InProgress" != *status)) { // dump is not in InProgress state, trace some info and change in // progress status lg2::info("{PATH}", "PATH", path); lg2::info("{STATUS}", "STATUS", *status); if ("xyz.openbmc_project.Common.Progress.OperationStatus." "Completed" == *status) { // Dump completed successfully progressStatus = DumpProgressStatus::Completed; } else { // Dump Failed progressStatus = DumpProgressStatus::Failed; } } } return 1; // non-negative return code for successful callback } /** * @brief Register a callback for dump progress status changes * * @param path - the object path of the dump to monitor * @param timeout - timeout - timeout interval in seconds */ void monitorDump(const std::string& path, const uint32_t timeout) { // callback will update progressStatus DumpProgressStatus progressStatus = DumpProgressStatus::InProgress; // setup the signal match rules and callback std::string matchInterface = "xyz.openbmc_project.Common.Progress"; auto bus = sdbusplus::bus::new_system(); std::unique_ptr match = std::make_unique( bus, sdbusplus::bus::match::rules::propertiesChanged( path.c_str(), matchInterface.c_str()), [&](auto& msg) { return dumpStatusChanged(msg, path, progressStatus); }); // wait for dump status to be completed (complete == true) // or until timeout interval bool timedOut = false; uint32_t secondsCount = 0; while ((DumpProgressStatus::InProgress == progressStatus) && !timedOut) { bus.wait(std::chrono::seconds(1)); bus.process_discard(); if (++secondsCount == timeout) { timedOut = true; } } if (timedOut) { lg2::error("Dump progress status did not change to " "complete within the timeout interval, exiting..."); } else if (DumpProgressStatus::Completed == progressStatus) { lg2::info("dump collection completed"); } else { lg2::info("dump collection failed"); } } void requestDump(const DumpParameters& dumpParameters) { constexpr auto path = "/xyz/openbmc_project/dump/system"; constexpr auto interface = "xyz.openbmc_project.Dump.Create"; constexpr auto function = "CreateDump"; sdbusplus::message_t method; if (0 == dbusMethod(path, interface, function, method)) { try { // dbus call arguments std::map> createParams; createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] = uint64_t(dumpParameters.logId); if (DumpType::Hostboot == dumpParameters.dumpType) { lg2::info("hostboot dump requested"); createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] = "com.ibm.Dump.Create.DumpType.Hostboot"; } else if (DumpType::SBE == dumpParameters.dumpType) { lg2::info("SBE dump requested"); createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] = "com.ibm.Dump.Create.DumpType.SBE"; createParams ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] = dumpParameters.unitId; } method.append(createParams); // using system dbus auto bus = sdbusplus::bus::new_system(); auto response = bus.call(method); // reply will be type dbus::ObjectPath sdbusplus::message::object_path reply; response.read(reply); // monitor dump progress monitorDump(reply, dumpParameters.timeout); } catch (const sdbusplus::exception_t& e) { constexpr auto ERROR_DUMP_DISABLED = "xyz.openbmc_project.Dump.Create.Error.Disabled"; if (e.name() == ERROR_DUMP_DISABLED) { // Dump is disabled, Skip the dump collection. lg2::info("Dump is disabled on({UNIT}), " "skipping dump collection", "UNIT", dumpParameters.unitId); } else { lg2::error("D-Bus call createDump exception OBJPATH={OBJPATH}, " "INTERFACE={INTERFACE}, EXCEPTION={ERROR}", "OBJPATH", path, "INTERFACE", interface, "ERROR", e); } } } } } // namespace dump } // namespace watchdog