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