1 #include "dump_monitor.hpp" 2 3 #include "dump_utils.hpp" 4 5 #include <phosphor-logging/lg2.hpp> 6 7 #include <regex> 8 9 namespace openpower::dump 10 { 11 12 constexpr auto dumpOutPath = "/var/lib/phosphor-debug-collector/opdump"; 13 constexpr auto dumpStatusFailed = 14 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"; 15 16 void DumpMonitor::executeCollectionScript( 17 const sdbusplus::message::object_path& path, const PropertyMap& properties) 18 { 19 std::vector<std::string> args = {"opdreport"}; 20 std::regex idFormat("^[a-fA-F0-9]{8}$"); 21 auto dumpIdStr = path.filename(); 22 if (!std::regex_match(dumpIdStr, idFormat)) 23 { 24 lg2::error("Failed to extract dump id from path {PATH}", "PATH", path); 25 updateProgressStatus(path, dumpStatusFailed); 26 return; 27 } 28 29 uint32_t dumpId = std::strtoul(dumpIdStr.c_str(), nullptr, 16); 30 int dumpType = getDumpTypeFromId(dumpId); 31 std::filesystem::path dumpPath = std::filesystem::path(dumpOutPath) / 32 dumpIdStr; 33 34 // Add type, ID, and dump path to args 35 args.push_back("-t"); 36 args.push_back(std::to_string(dumpType)); 37 args.push_back("-i"); 38 args.push_back(dumpIdStr); 39 args.push_back("-d"); 40 args.push_back(dumpPath.string()); 41 42 // Optionally add ErrorLogId and FailingUnitId 43 auto errorLogIdIt = properties.find("ErrorLogId"); 44 if (errorLogIdIt != properties.end()) 45 { 46 uint32_t errorLogId = std::get<uint32_t>(errorLogIdIt->second); 47 args.push_back("-e"); 48 args.push_back(std::to_string(errorLogId)); 49 } 50 51 auto failingUnitIdIt = properties.find("FailingUnitId"); 52 if (failingUnitIdIt != properties.end()) 53 { 54 uint32_t failingUnitId = std::get<uint32_t>(failingUnitIdIt->second); 55 args.push_back("-f"); 56 args.push_back(std::to_string(failingUnitId)); 57 } 58 59 std::vector<char*> argv; 60 for (auto& arg : args) 61 { 62 argv.push_back(arg.data()); 63 } 64 65 argv.push_back(nullptr); 66 pid_t pid = fork(); 67 if (pid == -1) 68 { 69 lg2::error("Failed to fork, cannot collect dump, {ERRRNO}", "ERRNO", 70 errno); 71 updateProgressStatus(path, dumpStatusFailed); 72 exit(EXIT_FAILURE); // Exit explicitly with failure status 73 } 74 else if (pid == 0) 75 { 76 // Child process 77 execvp("opdreport", argv.data()); 78 perror("execvp"); // execvp only returns on error 79 updateProgressStatus(path, dumpStatusFailed); 80 exit(EXIT_FAILURE); // Exit explicitly with failure status 81 } 82 else 83 { 84 // Parent process: wait for the child to terminate 85 int status; 86 waitpid(pid, &status, 0); 87 if (WIFEXITED(status)) 88 { 89 int exit_status = WEXITSTATUS(status); 90 91 if (exit_status != 0) 92 { 93 // Handle failure 94 lg2::error("Dump failed updating status {PATH}", "PATH", path); 95 updateProgressStatus(path, dumpStatusFailed); 96 } 97 } 98 } 99 } 100 101 void DumpMonitor::handleDBusSignal(sdbusplus::message_t& msg) 102 { 103 sdbusplus::message::object_path objectPath; 104 InterfaceMap interfaces; 105 106 msg.read(objectPath, interfaces); 107 108 lg2::info("Signal received at {PATH}: ", "PATH", objectPath); 109 110 // There can be new a entry created after the completion of the collection 111 // with completed status, so pick only entries with InProgress status. 112 if (isInProgress(interfaces)) 113 { 114 for (const auto& interfaceName : monitoredInterfaces) 115 { 116 auto it = interfaces.find(interfaceName); 117 if (it != interfaces.end()) 118 { 119 lg2::info("An entry created, collecting a new dump {DUMP}", 120 "DUMP", interfaceName); 121 executeCollectionScript(objectPath, it->second); 122 } 123 } 124 } 125 } 126 127 void DumpMonitor::updateProgressStatus(const std::string& path, 128 const std::string& status) 129 { 130 auto bus = sdbusplus::bus::new_default(); 131 const std::string interfaceName = "xyz.openbmc_project.Common.Progress"; 132 const std::string propertyName = "Status"; 133 const std::string serviceName = "xyz.openbmc_project.Dump.Manager"; 134 135 try 136 { 137 auto statusVariant = std::variant<std::string>(status); 138 util::setProperty<std::variant<std::string>>( 139 interfaceName, propertyName, path, bus, statusVariant); 140 lg2::info("Status updated successfully to {STATUS} {PATH}", "STATUS", 141 status, "PATH", path); 142 } 143 catch (const sdbusplus::exception_t& e) 144 { 145 lg2::error("Failed to update status {STATUS} {PATH} {ERROR}", "STATUS", 146 status, "PATH", path, "ERROR", e); 147 } 148 } 149 150 } // namespace openpower::dump 151