1 #include "watchdog_handler.hpp" 2 3 #include "watchdog_dbus.hpp" 4 #include "watchdog_logging.hpp" 5 6 #include <phosphor-logging/lg2.hpp> 7 #include <sdbusplus/bus.hpp> 8 #include <sdbusplus/bus/match.hpp> 9 10 namespace watchdog 11 { 12 namespace dump 13 { 14 15 /** 16 * @brief Callback for dump request properties change signal monitor 17 * 18 * @param msg - dbus message from the dbus match infrastructure 19 * @param path - the object path we are monitoring 20 * @param progressStatus - dump progress status 21 * @return Always non-zero indicating no error, no cascading callbacks 22 */ 23 uint dumpStatusChanged(sdbusplus::message_t& msg, std::string path, 24 DumpProgressStatus& progressStatus) 25 { 26 // reply (msg) will be a property change message 27 std::string interface; 28 std::map<std::string, std::variant<std::string, uint8_t>> property; 29 msg.read(interface, property); 30 31 // looking for property Status changes 32 std::string propertyType = "Status"; 33 auto dumpStatus = property.find(propertyType); 34 35 if (dumpStatus != property.end()) 36 { 37 const std::string* status = 38 std::get_if<std::string>(&(dumpStatus->second)); 39 40 if ((nullptr != status) && ("xyz.openbmc_project.Common.Progress." 41 "OperationStatus.InProgress" != *status)) 42 { 43 // dump is not in InProgress state, trace some info and change in 44 // progress status 45 lg2::info("{PATH}", "PATH", path); 46 lg2::info("{STATUS}", "STATUS", *status); 47 48 if ("xyz.openbmc_project.Common.Progress.OperationStatus." 49 "Completed" == *status) 50 { 51 // Dump completed successfully 52 progressStatus = DumpProgressStatus::Completed; 53 } 54 else 55 { 56 // Dump Failed 57 progressStatus = DumpProgressStatus::Failed; 58 } 59 } 60 } 61 62 return 1; // non-negative return code for successful callback 63 } 64 65 /** 66 * @brief Register a callback for dump progress status changes 67 * 68 * @param path - the object path of the dump to monitor 69 * @param timeout - timeout - timeout interval in seconds 70 */ 71 void monitorDump(const std::string& path, const uint32_t timeout) 72 { 73 // callback will update progressStatus 74 DumpProgressStatus progressStatus = DumpProgressStatus::InProgress; 75 76 // setup the signal match rules and callback 77 std::string matchInterface = "xyz.openbmc_project.Common.Progress"; 78 auto bus = sdbusplus::bus::new_system(); 79 80 std::unique_ptr<sdbusplus::bus::match_t> match = 81 std::make_unique<sdbusplus::bus::match_t>( 82 bus, 83 sdbusplus::bus::match::rules::propertiesChanged( 84 path.c_str(), matchInterface.c_str()), 85 [&](auto& msg) { 86 return dumpStatusChanged(msg, path, progressStatus); 87 }); 88 89 // wait for dump status to be completed (complete == true) 90 // or until timeout interval 91 92 bool timedOut = false; 93 uint32_t secondsCount = 0; 94 while ((DumpProgressStatus::InProgress == progressStatus) && !timedOut) 95 { 96 bus.wait(std::chrono::seconds(1)); 97 bus.process_discard(); 98 99 if (++secondsCount == timeout) 100 { 101 timedOut = true; 102 } 103 } 104 105 if (timedOut) 106 { 107 lg2::error("Dump progress status did not change to " 108 "complete within the timeout interval, exiting..."); 109 } 110 else if (DumpProgressStatus::Completed == progressStatus) 111 { 112 lg2::info("dump collection completed"); 113 } 114 else 115 { 116 lg2::info("dump collection failed"); 117 } 118 } 119 120 void requestDump(const DumpParameters& dumpParameters) 121 { 122 constexpr auto path = "/xyz/openbmc_project/dump/system"; 123 constexpr auto interface = "xyz.openbmc_project.Dump.Create"; 124 constexpr auto function = "CreateDump"; 125 126 sdbusplus::message_t method; 127 128 if (0 == dbusMethod(path, interface, function, method)) 129 { 130 try 131 { 132 // dbus call arguments 133 std::map<std::string, std::variant<std::string, uint64_t>> 134 createParams; 135 createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] = 136 uint64_t(dumpParameters.logId); 137 if (DumpType::Hostboot == dumpParameters.dumpType) 138 { 139 lg2::info("hostboot dump requested"); 140 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] = 141 "com.ibm.Dump.Create.DumpType.Hostboot"; 142 } 143 else if (DumpType::SBE == dumpParameters.dumpType) 144 { 145 lg2::info("SBE dump requested"); 146 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] = 147 "com.ibm.Dump.Create.DumpType.SBE"; 148 createParams 149 ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] = 150 dumpParameters.unitId; 151 } 152 153 method.append(createParams); 154 155 // using system dbus 156 auto bus = sdbusplus::bus::new_system(); 157 auto response = bus.call(method); 158 159 // reply will be type dbus::ObjectPath 160 sdbusplus::message::object_path reply; 161 response.read(reply); 162 163 // monitor dump progress 164 monitorDump(reply, dumpParameters.timeout); 165 } 166 catch (const sdbusplus::exception_t& e) 167 { 168 constexpr auto ERROR_DUMP_DISABLED = 169 "xyz.openbmc_project.Dump.Create.Error.Disabled"; 170 if (e.name() == ERROR_DUMP_DISABLED) 171 { 172 // Dump is disabled, Skip the dump collection. 173 lg2::info("Dump is disabled on({UNIT}), " 174 "skipping dump collection", 175 "UNIT", dumpParameters.unitId); 176 } 177 else 178 { 179 lg2::error("D-Bus call createDump exception OBJPATH={OBJPATH}, " 180 "INTERFACE={INTERFACE}, EXCEPTION={ERROR}", 181 "OBJPATH", path, "INTERFACE", interface, "ERROR", e); 182 } 183 } 184 } 185 } 186 187 } // namespace dump 188 } // namespace watchdog 189