1a07f34fcSDhruvaraj Subhashchandran #include "dump_monitor.hpp"
2a07f34fcSDhruvaraj Subhashchandran 
3a07f34fcSDhruvaraj Subhashchandran #include "dump_utils.hpp"
4a07f34fcSDhruvaraj Subhashchandran 
5a07f34fcSDhruvaraj Subhashchandran #include <phosphor-logging/lg2.hpp>
6a07f34fcSDhruvaraj Subhashchandran 
7a07f34fcSDhruvaraj Subhashchandran #include <regex>
8a07f34fcSDhruvaraj Subhashchandran 
9a07f34fcSDhruvaraj Subhashchandran namespace openpower::dump
10a07f34fcSDhruvaraj Subhashchandran {
11a07f34fcSDhruvaraj Subhashchandran 
12a07f34fcSDhruvaraj Subhashchandran constexpr auto dumpOutPath = "/var/lib/phosphor-debug-collector/opdump";
13a07f34fcSDhruvaraj Subhashchandran constexpr auto dumpStatusFailed =
14a07f34fcSDhruvaraj Subhashchandran     "xyz.openbmc_project.Common.Progress.OperationStatus.Failed";
15a07f34fcSDhruvaraj Subhashchandran 
executeCollectionScript(const sdbusplus::message::object_path & path,const PropertyMap & properties)16a07f34fcSDhruvaraj Subhashchandran void DumpMonitor::executeCollectionScript(
17a07f34fcSDhruvaraj Subhashchandran     const sdbusplus::message::object_path& path, const PropertyMap& properties)
18a07f34fcSDhruvaraj Subhashchandran {
19a07f34fcSDhruvaraj Subhashchandran     std::vector<std::string> args = {"opdreport"};
20a07f34fcSDhruvaraj Subhashchandran     std::regex idFormat("^[a-fA-F0-9]{8}$");
21a07f34fcSDhruvaraj Subhashchandran     auto dumpIdStr = path.filename();
22a07f34fcSDhruvaraj Subhashchandran     if (!std::regex_match(dumpIdStr, idFormat))
23a07f34fcSDhruvaraj Subhashchandran     {
24a07f34fcSDhruvaraj Subhashchandran         lg2::error("Failed to extract dump id from path {PATH}", "PATH", path);
25a07f34fcSDhruvaraj Subhashchandran         updateProgressStatus(path, dumpStatusFailed);
26a07f34fcSDhruvaraj Subhashchandran         return;
27a07f34fcSDhruvaraj Subhashchandran     }
28a07f34fcSDhruvaraj Subhashchandran 
29a07f34fcSDhruvaraj Subhashchandran     uint32_t dumpId = std::strtoul(dumpIdStr.c_str(), nullptr, 16);
30a07f34fcSDhruvaraj Subhashchandran     int dumpType = getDumpTypeFromId(dumpId);
31*540521edSPatrick Williams     std::filesystem::path dumpPath =
32*540521edSPatrick Williams         std::filesystem::path(dumpOutPath) / dumpIdStr;
33a07f34fcSDhruvaraj Subhashchandran 
34a07f34fcSDhruvaraj Subhashchandran     // Add type, ID, and dump path to args
35a07f34fcSDhruvaraj Subhashchandran     args.push_back("-t");
36a07f34fcSDhruvaraj Subhashchandran     args.push_back(std::to_string(dumpType));
37a07f34fcSDhruvaraj Subhashchandran     args.push_back("-i");
38a07f34fcSDhruvaraj Subhashchandran     args.push_back(dumpIdStr);
39a07f34fcSDhruvaraj Subhashchandran     args.push_back("-d");
40a07f34fcSDhruvaraj Subhashchandran     args.push_back(dumpPath.string());
41a07f34fcSDhruvaraj Subhashchandran 
42a07f34fcSDhruvaraj Subhashchandran     // Optionally add ErrorLogId and FailingUnitId
43a07f34fcSDhruvaraj Subhashchandran     auto errorLogIdIt = properties.find("ErrorLogId");
44a07f34fcSDhruvaraj Subhashchandran     if (errorLogIdIt != properties.end())
45a07f34fcSDhruvaraj Subhashchandran     {
46a07f34fcSDhruvaraj Subhashchandran         uint32_t errorLogId = std::get<uint32_t>(errorLogIdIt->second);
47a07f34fcSDhruvaraj Subhashchandran         args.push_back("-e");
48a07f34fcSDhruvaraj Subhashchandran         args.push_back(std::to_string(errorLogId));
49a07f34fcSDhruvaraj Subhashchandran     }
50a07f34fcSDhruvaraj Subhashchandran 
51a07f34fcSDhruvaraj Subhashchandran     auto failingUnitIdIt = properties.find("FailingUnitId");
52a07f34fcSDhruvaraj Subhashchandran     if (failingUnitIdIt != properties.end())
53a07f34fcSDhruvaraj Subhashchandran     {
54a07f34fcSDhruvaraj Subhashchandran         uint32_t failingUnitId = std::get<uint32_t>(failingUnitIdIt->second);
55a07f34fcSDhruvaraj Subhashchandran         args.push_back("-f");
56a07f34fcSDhruvaraj Subhashchandran         args.push_back(std::to_string(failingUnitId));
57a07f34fcSDhruvaraj Subhashchandran     }
58a07f34fcSDhruvaraj Subhashchandran 
59a07f34fcSDhruvaraj Subhashchandran     std::vector<char*> argv;
60a07f34fcSDhruvaraj Subhashchandran     for (auto& arg : args)
61a07f34fcSDhruvaraj Subhashchandran     {
62a07f34fcSDhruvaraj Subhashchandran         argv.push_back(arg.data());
63a07f34fcSDhruvaraj Subhashchandran     }
64a07f34fcSDhruvaraj Subhashchandran 
65a07f34fcSDhruvaraj Subhashchandran     argv.push_back(nullptr);
66a07f34fcSDhruvaraj Subhashchandran     pid_t pid = fork();
67a07f34fcSDhruvaraj Subhashchandran     if (pid == -1)
68a07f34fcSDhruvaraj Subhashchandran     {
69a07f34fcSDhruvaraj Subhashchandran         lg2::error("Failed to fork, cannot collect dump, {ERRRNO}", "ERRNO",
70a07f34fcSDhruvaraj Subhashchandran                    errno);
71a07f34fcSDhruvaraj Subhashchandran         updateProgressStatus(path, dumpStatusFailed);
72a07f34fcSDhruvaraj Subhashchandran         exit(EXIT_FAILURE); // Exit explicitly with failure status
73a07f34fcSDhruvaraj Subhashchandran     }
74a07f34fcSDhruvaraj Subhashchandran     else if (pid == 0)
75a07f34fcSDhruvaraj Subhashchandran     {
76a07f34fcSDhruvaraj Subhashchandran         // Child process
77a07f34fcSDhruvaraj Subhashchandran         execvp("opdreport", argv.data());
78a07f34fcSDhruvaraj Subhashchandran         perror("execvp");   // execvp only returns on error
79a07f34fcSDhruvaraj Subhashchandran         updateProgressStatus(path, dumpStatusFailed);
80a07f34fcSDhruvaraj Subhashchandran         exit(EXIT_FAILURE); // Exit explicitly with failure status
81a07f34fcSDhruvaraj Subhashchandran     }
82a07f34fcSDhruvaraj Subhashchandran     else
83a07f34fcSDhruvaraj Subhashchandran     {
84a07f34fcSDhruvaraj Subhashchandran         // Parent process: wait for the child to terminate
85a07f34fcSDhruvaraj Subhashchandran         int status;
86a07f34fcSDhruvaraj Subhashchandran         waitpid(pid, &status, 0);
87a07f34fcSDhruvaraj Subhashchandran         if (WIFEXITED(status))
88a07f34fcSDhruvaraj Subhashchandran         {
89a07f34fcSDhruvaraj Subhashchandran             int exit_status = WEXITSTATUS(status);
90a07f34fcSDhruvaraj Subhashchandran 
91a07f34fcSDhruvaraj Subhashchandran             if (exit_status != 0)
92a07f34fcSDhruvaraj Subhashchandran             {
93a07f34fcSDhruvaraj Subhashchandran                 // Handle failure
94a07f34fcSDhruvaraj Subhashchandran                 lg2::error("Dump failed updating status {PATH}", "PATH", path);
95a07f34fcSDhruvaraj Subhashchandran                 updateProgressStatus(path, dumpStatusFailed);
96a07f34fcSDhruvaraj Subhashchandran             }
97a07f34fcSDhruvaraj Subhashchandran         }
98a07f34fcSDhruvaraj Subhashchandran     }
99a07f34fcSDhruvaraj Subhashchandran }
100a07f34fcSDhruvaraj Subhashchandran 
handleDBusSignal(sdbusplus::message_t & msg)101a4a34814SPatrick Williams void DumpMonitor::handleDBusSignal(sdbusplus::message_t& msg)
102a07f34fcSDhruvaraj Subhashchandran {
103a07f34fcSDhruvaraj Subhashchandran     sdbusplus::message::object_path objectPath;
104a07f34fcSDhruvaraj Subhashchandran     InterfaceMap interfaces;
105a07f34fcSDhruvaraj Subhashchandran 
106a07f34fcSDhruvaraj Subhashchandran     msg.read(objectPath, interfaces);
107a07f34fcSDhruvaraj Subhashchandran 
108a07f34fcSDhruvaraj Subhashchandran     lg2::info("Signal received at {PATH}: ", "PATH", objectPath);
109a07f34fcSDhruvaraj Subhashchandran 
110a07f34fcSDhruvaraj Subhashchandran     // There can be new a entry created after the completion of the collection
111a07f34fcSDhruvaraj Subhashchandran     // with completed status, so pick only entries with InProgress status.
112a07f34fcSDhruvaraj Subhashchandran     if (isInProgress(interfaces))
113a07f34fcSDhruvaraj Subhashchandran     {
114a07f34fcSDhruvaraj Subhashchandran         for (const auto& interfaceName : monitoredInterfaces)
115a07f34fcSDhruvaraj Subhashchandran         {
116a07f34fcSDhruvaraj Subhashchandran             auto it = interfaces.find(interfaceName);
117a07f34fcSDhruvaraj Subhashchandran             if (it != interfaces.end())
118a07f34fcSDhruvaraj Subhashchandran             {
119a07f34fcSDhruvaraj Subhashchandran                 lg2::info("An entry created, collecting a new dump {DUMP}",
120a07f34fcSDhruvaraj Subhashchandran                           "DUMP", interfaceName);
1216cc176ecSDhruvaraj Subhashchandran                 initiateDumpCollection(objectPath, interfaceName, it->second);
122a07f34fcSDhruvaraj Subhashchandran             }
123a07f34fcSDhruvaraj Subhashchandran         }
124a07f34fcSDhruvaraj Subhashchandran     }
125a07f34fcSDhruvaraj Subhashchandran }
126a07f34fcSDhruvaraj Subhashchandran 
updateProgressStatus(const std::string & path,const std::string & status)127a07f34fcSDhruvaraj Subhashchandran void DumpMonitor::updateProgressStatus(const std::string& path,
128a07f34fcSDhruvaraj Subhashchandran                                        const std::string& status)
129a07f34fcSDhruvaraj Subhashchandran {
130a07f34fcSDhruvaraj Subhashchandran     auto bus = sdbusplus::bus::new_default();
131a07f34fcSDhruvaraj Subhashchandran     const std::string interfaceName = "xyz.openbmc_project.Common.Progress";
132a07f34fcSDhruvaraj Subhashchandran     const std::string propertyName = "Status";
133a07f34fcSDhruvaraj Subhashchandran     const std::string serviceName = "xyz.openbmc_project.Dump.Manager";
134a07f34fcSDhruvaraj Subhashchandran 
135a07f34fcSDhruvaraj Subhashchandran     try
136a07f34fcSDhruvaraj Subhashchandran     {
137a07f34fcSDhruvaraj Subhashchandran         auto statusVariant = std::variant<std::string>(status);
138a07f34fcSDhruvaraj Subhashchandran         util::setProperty<std::variant<std::string>>(
139a07f34fcSDhruvaraj Subhashchandran             interfaceName, propertyName, path, bus, statusVariant);
140a07f34fcSDhruvaraj Subhashchandran         lg2::info("Status updated successfully to {STATUS} {PATH}", "STATUS",
141a07f34fcSDhruvaraj Subhashchandran                   status, "PATH", path);
142a07f34fcSDhruvaraj Subhashchandran     }
143a07f34fcSDhruvaraj Subhashchandran     catch (const sdbusplus::exception_t& e)
144a07f34fcSDhruvaraj Subhashchandran     {
145a07f34fcSDhruvaraj Subhashchandran         lg2::error("Failed to update status {STATUS} {PATH} {ERROR}", "STATUS",
146a07f34fcSDhruvaraj Subhashchandran                    status, "PATH", path, "ERROR", e);
147a07f34fcSDhruvaraj Subhashchandran     }
148a07f34fcSDhruvaraj Subhashchandran }
149a07f34fcSDhruvaraj Subhashchandran 
startMpReboot(const sdbusplus::message::object_path & objectPath)1506cc176ecSDhruvaraj Subhashchandran void DumpMonitor::startMpReboot(
1516cc176ecSDhruvaraj Subhashchandran     const sdbusplus::message::object_path& objectPath)
1526cc176ecSDhruvaraj Subhashchandran {
1536cc176ecSDhruvaraj Subhashchandran     constexpr auto systemdService = "org.freedesktop.systemd1";
1546cc176ecSDhruvaraj Subhashchandran     constexpr auto systemdObjPath = "/org/freedesktop/systemd1";
1556cc176ecSDhruvaraj Subhashchandran     constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1566cc176ecSDhruvaraj Subhashchandran     constexpr auto diagModeTarget = "obmc-host-crash@0.target";
1576cc176ecSDhruvaraj Subhashchandran 
1586cc176ecSDhruvaraj Subhashchandran     try
1596cc176ecSDhruvaraj Subhashchandran     {
1606cc176ecSDhruvaraj Subhashchandran         auto b = sdbusplus::bus::new_default();
1616cc176ecSDhruvaraj Subhashchandran         auto method = b.new_method_call(systemdService, systemdObjPath,
1626cc176ecSDhruvaraj Subhashchandran                                         systemdInterface, "StartUnit");
1636cc176ecSDhruvaraj Subhashchandran         method.append(diagModeTarget); // unit to activate
1646cc176ecSDhruvaraj Subhashchandran         method.append("replace");
1656cc176ecSDhruvaraj Subhashchandran         b.call_noreply(method);
1666cc176ecSDhruvaraj Subhashchandran     }
1676cc176ecSDhruvaraj Subhashchandran     catch (const sdbusplus::exception_t& e)
1686cc176ecSDhruvaraj Subhashchandran     {
1696cc176ecSDhruvaraj Subhashchandran         lg2::error("Failed to start memory preserving reboot");
1706cc176ecSDhruvaraj Subhashchandran         updateProgressStatus(objectPath, dumpStatusFailed);
1716cc176ecSDhruvaraj Subhashchandran     }
1726cc176ecSDhruvaraj Subhashchandran }
1736cc176ecSDhruvaraj Subhashchandran 
initiateDumpCollection(const std::string & path,const std::string & intf,const PropertyMap & properties)1746cc176ecSDhruvaraj Subhashchandran void DumpMonitor::initiateDumpCollection(const std::string& path,
1756cc176ecSDhruvaraj Subhashchandran                                          const std::string& intf,
1766cc176ecSDhruvaraj Subhashchandran                                          const PropertyMap& properties)
1776cc176ecSDhruvaraj Subhashchandran {
1786cc176ecSDhruvaraj Subhashchandran     using namespace sdbusplus::common::xyz::openbmc_project::dump::entry;
1796cc176ecSDhruvaraj Subhashchandran     if (intf == System::interface)
1806cc176ecSDhruvaraj Subhashchandran     {
1816cc176ecSDhruvaraj Subhashchandran         // Find the SystemImpact property, if this property is not
1826cc176ecSDhruvaraj Subhashchandran         // available assume disruptive.
1836cc176ecSDhruvaraj Subhashchandran         auto systemImpactIt = properties.find("SystemImpact");
1846cc176ecSDhruvaraj Subhashchandran         if (systemImpactIt != properties.end() &&
1856cc176ecSDhruvaraj Subhashchandran             std::get<std::string>(systemImpactIt->second) !=
1866cc176ecSDhruvaraj Subhashchandran                 System::convertSystemImpactToString(
1876cc176ecSDhruvaraj Subhashchandran                     System::SystemImpact::Disruptive))
1886cc176ecSDhruvaraj Subhashchandran         {
1896cc176ecSDhruvaraj Subhashchandran             lg2::info("Ignoring non-disruptive system dump {PATH}", "PATH",
1906cc176ecSDhruvaraj Subhashchandran                       path);
1916cc176ecSDhruvaraj Subhashchandran             return;
1926cc176ecSDhruvaraj Subhashchandran         }
1936cc176ecSDhruvaraj Subhashchandran         startMpReboot(path);
1946cc176ecSDhruvaraj Subhashchandran     }
1956cc176ecSDhruvaraj Subhashchandran     else
1966cc176ecSDhruvaraj Subhashchandran     {
1976cc176ecSDhruvaraj Subhashchandran         executeCollectionScript(path, properties);
1986cc176ecSDhruvaraj Subhashchandran     }
1996cc176ecSDhruvaraj Subhashchandran }
2006cc176ecSDhruvaraj Subhashchandran 
201a07f34fcSDhruvaraj Subhashchandran } // namespace openpower::dump
202