xref: /openbmc/phosphor-debug-collector/dump_manager_bmc.cpp (revision fef66a951fe6fe283515480b2c493dfdc2275a95)
1*fef66a95SDhruvaraj Subhashchandran #include "config.h"
2*fef66a95SDhruvaraj Subhashchandran 
3*fef66a95SDhruvaraj Subhashchandran #include "dump_manager_bmc.hpp"
4*fef66a95SDhruvaraj Subhashchandran 
5*fef66a95SDhruvaraj Subhashchandran #include "bmc_dump_entry.hpp"
6*fef66a95SDhruvaraj Subhashchandran #include "dump_internal.hpp"
7*fef66a95SDhruvaraj Subhashchandran #include "xyz/openbmc_project/Common/error.hpp"
8*fef66a95SDhruvaraj Subhashchandran #include "xyz/openbmc_project/Dump/Create/error.hpp"
9*fef66a95SDhruvaraj Subhashchandran 
10*fef66a95SDhruvaraj Subhashchandran #include <sys/inotify.h>
11*fef66a95SDhruvaraj Subhashchandran #include <unistd.h>
12*fef66a95SDhruvaraj Subhashchandran 
13*fef66a95SDhruvaraj Subhashchandran #include <phosphor-logging/elog-errors.hpp>
14*fef66a95SDhruvaraj Subhashchandran #include <phosphor-logging/elog.hpp>
15*fef66a95SDhruvaraj Subhashchandran #include <regex>
16*fef66a95SDhruvaraj Subhashchandran 
17*fef66a95SDhruvaraj Subhashchandran namespace phosphor
18*fef66a95SDhruvaraj Subhashchandran {
19*fef66a95SDhruvaraj Subhashchandran namespace dump
20*fef66a95SDhruvaraj Subhashchandran {
21*fef66a95SDhruvaraj Subhashchandran namespace bmc
22*fef66a95SDhruvaraj Subhashchandran {
23*fef66a95SDhruvaraj Subhashchandran 
24*fef66a95SDhruvaraj Subhashchandran using namespace sdbusplus::xyz::openbmc_project::Common::Error;
25*fef66a95SDhruvaraj Subhashchandran using namespace phosphor::logging;
26*fef66a95SDhruvaraj Subhashchandran 
27*fef66a95SDhruvaraj Subhashchandran namespace internal
28*fef66a95SDhruvaraj Subhashchandran {
29*fef66a95SDhruvaraj Subhashchandran 
30*fef66a95SDhruvaraj Subhashchandran void Manager::create(Type type, std::vector<std::string> fullPaths)
31*fef66a95SDhruvaraj Subhashchandran {
32*fef66a95SDhruvaraj Subhashchandran     dumpMgr.phosphor::dump::bmc::Manager::captureDump(type, fullPaths);
33*fef66a95SDhruvaraj Subhashchandran }
34*fef66a95SDhruvaraj Subhashchandran 
35*fef66a95SDhruvaraj Subhashchandran } // namespace internal
36*fef66a95SDhruvaraj Subhashchandran 
37*fef66a95SDhruvaraj Subhashchandran uint32_t Manager::createDump()
38*fef66a95SDhruvaraj Subhashchandran {
39*fef66a95SDhruvaraj Subhashchandran     std::vector<std::string> paths;
40*fef66a95SDhruvaraj Subhashchandran     return captureDump(Type::UserRequested, paths);
41*fef66a95SDhruvaraj Subhashchandran }
42*fef66a95SDhruvaraj Subhashchandran 
43*fef66a95SDhruvaraj Subhashchandran uint32_t Manager::captureDump(Type type,
44*fef66a95SDhruvaraj Subhashchandran                               const std::vector<std::string>& fullPaths)
45*fef66a95SDhruvaraj Subhashchandran {
46*fef66a95SDhruvaraj Subhashchandran     // Get Dump size.
47*fef66a95SDhruvaraj Subhashchandran     auto size = getAllowedSize();
48*fef66a95SDhruvaraj Subhashchandran 
49*fef66a95SDhruvaraj Subhashchandran     pid_t pid = fork();
50*fef66a95SDhruvaraj Subhashchandran 
51*fef66a95SDhruvaraj Subhashchandran     if (pid == 0)
52*fef66a95SDhruvaraj Subhashchandran     {
53*fef66a95SDhruvaraj Subhashchandran         fs::path dumpPath(dumpDir);
54*fef66a95SDhruvaraj Subhashchandran         auto id = std::to_string(lastEntryId + 1);
55*fef66a95SDhruvaraj Subhashchandran         dumpPath /= id;
56*fef66a95SDhruvaraj Subhashchandran 
57*fef66a95SDhruvaraj Subhashchandran         // get dreport type map entry
58*fef66a95SDhruvaraj Subhashchandran         auto tempType = TypeMap.find(type);
59*fef66a95SDhruvaraj Subhashchandran 
60*fef66a95SDhruvaraj Subhashchandran         execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
61*fef66a95SDhruvaraj Subhashchandran               id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
62*fef66a95SDhruvaraj Subhashchandran               fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
63*fef66a95SDhruvaraj Subhashchandran               tempType->second.c_str(), nullptr);
64*fef66a95SDhruvaraj Subhashchandran 
65*fef66a95SDhruvaraj Subhashchandran         // dreport script execution is failed.
66*fef66a95SDhruvaraj Subhashchandran         auto error = errno;
67*fef66a95SDhruvaraj Subhashchandran         log<level::ERR>("Error occurred during dreport function execution",
68*fef66a95SDhruvaraj Subhashchandran                         entry("ERRNO=%d", error));
69*fef66a95SDhruvaraj Subhashchandran         elog<InternalFailure>();
70*fef66a95SDhruvaraj Subhashchandran     }
71*fef66a95SDhruvaraj Subhashchandran     else if (pid > 0)
72*fef66a95SDhruvaraj Subhashchandran     {
73*fef66a95SDhruvaraj Subhashchandran         auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
74*fef66a95SDhruvaraj Subhashchandran                                      WEXITED | WSTOPPED, callback, nullptr);
75*fef66a95SDhruvaraj Subhashchandran         if (0 > rc)
76*fef66a95SDhruvaraj Subhashchandran         {
77*fef66a95SDhruvaraj Subhashchandran             // Failed to add to event loop
78*fef66a95SDhruvaraj Subhashchandran             log<level::ERR>("Error occurred during the sd_event_add_child call",
79*fef66a95SDhruvaraj Subhashchandran                             entry("RC=%d", rc));
80*fef66a95SDhruvaraj Subhashchandran             elog<InternalFailure>();
81*fef66a95SDhruvaraj Subhashchandran         }
82*fef66a95SDhruvaraj Subhashchandran     }
83*fef66a95SDhruvaraj Subhashchandran     else
84*fef66a95SDhruvaraj Subhashchandran     {
85*fef66a95SDhruvaraj Subhashchandran         auto error = errno;
86*fef66a95SDhruvaraj Subhashchandran         log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
87*fef66a95SDhruvaraj Subhashchandran         elog<InternalFailure>();
88*fef66a95SDhruvaraj Subhashchandran     }
89*fef66a95SDhruvaraj Subhashchandran 
90*fef66a95SDhruvaraj Subhashchandran     return ++lastEntryId;
91*fef66a95SDhruvaraj Subhashchandran }
92*fef66a95SDhruvaraj Subhashchandran 
93*fef66a95SDhruvaraj Subhashchandran void Manager::createEntry(const fs::path& file)
94*fef66a95SDhruvaraj Subhashchandran {
95*fef66a95SDhruvaraj Subhashchandran     // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
96*fef66a95SDhruvaraj Subhashchandran     static constexpr auto ID_POS = 1;
97*fef66a95SDhruvaraj Subhashchandran     static constexpr auto EPOCHTIME_POS = 2;
98*fef66a95SDhruvaraj Subhashchandran     std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
99*fef66a95SDhruvaraj Subhashchandran 
100*fef66a95SDhruvaraj Subhashchandran     std::smatch match;
101*fef66a95SDhruvaraj Subhashchandran     std::string name = file.filename();
102*fef66a95SDhruvaraj Subhashchandran 
103*fef66a95SDhruvaraj Subhashchandran     if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
104*fef66a95SDhruvaraj Subhashchandran     {
105*fef66a95SDhruvaraj Subhashchandran         log<level::ERR>("Invalid Dump file name",
106*fef66a95SDhruvaraj Subhashchandran                         entry("FILENAME=%s", file.filename().c_str()));
107*fef66a95SDhruvaraj Subhashchandran         return;
108*fef66a95SDhruvaraj Subhashchandran     }
109*fef66a95SDhruvaraj Subhashchandran 
110*fef66a95SDhruvaraj Subhashchandran     auto idString = match[ID_POS];
111*fef66a95SDhruvaraj Subhashchandran     auto msString = match[EPOCHTIME_POS];
112*fef66a95SDhruvaraj Subhashchandran 
113*fef66a95SDhruvaraj Subhashchandran     try
114*fef66a95SDhruvaraj Subhashchandran     {
115*fef66a95SDhruvaraj Subhashchandran         auto id = stoul(idString);
116*fef66a95SDhruvaraj Subhashchandran         // Entry Object path.
117*fef66a95SDhruvaraj Subhashchandran         auto objPath = fs::path(baseEntryPath) / std::to_string(id);
118*fef66a95SDhruvaraj Subhashchandran 
119*fef66a95SDhruvaraj Subhashchandran         entries.insert(
120*fef66a95SDhruvaraj Subhashchandran             std::make_pair(id, std::make_unique<bmc::Entry>(
121*fef66a95SDhruvaraj Subhashchandran                                    bus, objPath.c_str(), id, stoull(msString),
122*fef66a95SDhruvaraj Subhashchandran                                    fs::file_size(file), file, *this)));
123*fef66a95SDhruvaraj Subhashchandran     }
124*fef66a95SDhruvaraj Subhashchandran     catch (const std::invalid_argument& e)
125*fef66a95SDhruvaraj Subhashchandran     {
126*fef66a95SDhruvaraj Subhashchandran         log<level::ERR>(e.what());
127*fef66a95SDhruvaraj Subhashchandran         return;
128*fef66a95SDhruvaraj Subhashchandran     }
129*fef66a95SDhruvaraj Subhashchandran }
130*fef66a95SDhruvaraj Subhashchandran 
131*fef66a95SDhruvaraj Subhashchandran void Manager::watchCallback(const UserMap& fileInfo)
132*fef66a95SDhruvaraj Subhashchandran {
133*fef66a95SDhruvaraj Subhashchandran     for (const auto& i : fileInfo)
134*fef66a95SDhruvaraj Subhashchandran     {
135*fef66a95SDhruvaraj Subhashchandran         // For any new dump file create dump entry object
136*fef66a95SDhruvaraj Subhashchandran         // and associated inotify watch.
137*fef66a95SDhruvaraj Subhashchandran         if (IN_CLOSE_WRITE == i.second)
138*fef66a95SDhruvaraj Subhashchandran         {
139*fef66a95SDhruvaraj Subhashchandran             removeWatch(i.first);
140*fef66a95SDhruvaraj Subhashchandran 
141*fef66a95SDhruvaraj Subhashchandran             createEntry(i.first);
142*fef66a95SDhruvaraj Subhashchandran         }
143*fef66a95SDhruvaraj Subhashchandran         // Start inotify watch on newly created directory.
144*fef66a95SDhruvaraj Subhashchandran         else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
145*fef66a95SDhruvaraj Subhashchandran         {
146*fef66a95SDhruvaraj Subhashchandran             auto watchObj = std::make_unique<Watch>(
147*fef66a95SDhruvaraj Subhashchandran                 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
148*fef66a95SDhruvaraj Subhashchandran                 std::bind(
149*fef66a95SDhruvaraj Subhashchandran                     std::mem_fn(&phosphor::dump::bmc::Manager::watchCallback),
150*fef66a95SDhruvaraj Subhashchandran                     this, std::placeholders::_1));
151*fef66a95SDhruvaraj Subhashchandran 
152*fef66a95SDhruvaraj Subhashchandran             childWatchMap.emplace(i.first, std::move(watchObj));
153*fef66a95SDhruvaraj Subhashchandran         }
154*fef66a95SDhruvaraj Subhashchandran     }
155*fef66a95SDhruvaraj Subhashchandran }
156*fef66a95SDhruvaraj Subhashchandran 
157*fef66a95SDhruvaraj Subhashchandran void Manager::removeWatch(const fs::path& path)
158*fef66a95SDhruvaraj Subhashchandran {
159*fef66a95SDhruvaraj Subhashchandran     // Delete Watch entry from map.
160*fef66a95SDhruvaraj Subhashchandran     childWatchMap.erase(path);
161*fef66a95SDhruvaraj Subhashchandran }
162*fef66a95SDhruvaraj Subhashchandran 
163*fef66a95SDhruvaraj Subhashchandran void Manager::restore()
164*fef66a95SDhruvaraj Subhashchandran {
165*fef66a95SDhruvaraj Subhashchandran     fs::path dir(dumpDir);
166*fef66a95SDhruvaraj Subhashchandran     if (!fs::exists(dir) || fs::is_empty(dir))
167*fef66a95SDhruvaraj Subhashchandran     {
168*fef66a95SDhruvaraj Subhashchandran         return;
169*fef66a95SDhruvaraj Subhashchandran     }
170*fef66a95SDhruvaraj Subhashchandran 
171*fef66a95SDhruvaraj Subhashchandran     // Dump file path: <DUMP_PATH>/<id>/<filename>
172*fef66a95SDhruvaraj Subhashchandran     for (const auto& p : fs::directory_iterator(dir))
173*fef66a95SDhruvaraj Subhashchandran     {
174*fef66a95SDhruvaraj Subhashchandran         auto idStr = p.path().filename().string();
175*fef66a95SDhruvaraj Subhashchandran 
176*fef66a95SDhruvaraj Subhashchandran         // Consider only directory's with dump id as name.
177*fef66a95SDhruvaraj Subhashchandran         // Note: As per design one file per directory.
178*fef66a95SDhruvaraj Subhashchandran         if ((fs::is_directory(p.path())) &&
179*fef66a95SDhruvaraj Subhashchandran             std::all_of(idStr.begin(), idStr.end(), ::isdigit))
180*fef66a95SDhruvaraj Subhashchandran         {
181*fef66a95SDhruvaraj Subhashchandran             lastEntryId =
182*fef66a95SDhruvaraj Subhashchandran                 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
183*fef66a95SDhruvaraj Subhashchandran             auto fileIt = fs::directory_iterator(p.path());
184*fef66a95SDhruvaraj Subhashchandran             // Create dump entry d-bus object.
185*fef66a95SDhruvaraj Subhashchandran             if (fileIt != fs::end(fileIt))
186*fef66a95SDhruvaraj Subhashchandran             {
187*fef66a95SDhruvaraj Subhashchandran                 createEntry(fileIt->path());
188*fef66a95SDhruvaraj Subhashchandran             }
189*fef66a95SDhruvaraj Subhashchandran         }
190*fef66a95SDhruvaraj Subhashchandran     }
191*fef66a95SDhruvaraj Subhashchandran }
192*fef66a95SDhruvaraj Subhashchandran 
193*fef66a95SDhruvaraj Subhashchandran size_t Manager::getAllowedSize()
194*fef66a95SDhruvaraj Subhashchandran {
195*fef66a95SDhruvaraj Subhashchandran     using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
196*fef66a95SDhruvaraj Subhashchandran     using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
197*fef66a95SDhruvaraj Subhashchandran 
198*fef66a95SDhruvaraj Subhashchandran     auto size = 0;
199*fef66a95SDhruvaraj Subhashchandran 
200*fef66a95SDhruvaraj Subhashchandran     // Get current size of the dump directory.
201*fef66a95SDhruvaraj Subhashchandran     for (const auto& p : fs::recursive_directory_iterator(dumpDir))
202*fef66a95SDhruvaraj Subhashchandran     {
203*fef66a95SDhruvaraj Subhashchandran         if (!fs::is_directory(p))
204*fef66a95SDhruvaraj Subhashchandran         {
205*fef66a95SDhruvaraj Subhashchandran             size += fs::file_size(p);
206*fef66a95SDhruvaraj Subhashchandran         }
207*fef66a95SDhruvaraj Subhashchandran     }
208*fef66a95SDhruvaraj Subhashchandran 
209*fef66a95SDhruvaraj Subhashchandran     // Convert size into KB
210*fef66a95SDhruvaraj Subhashchandran     size = size / 1024;
211*fef66a95SDhruvaraj Subhashchandran 
212*fef66a95SDhruvaraj Subhashchandran     // Set the Dump size to Maximum  if the free space is greater than
213*fef66a95SDhruvaraj Subhashchandran     // Dump max size otherwise return the available size.
214*fef66a95SDhruvaraj Subhashchandran 
215*fef66a95SDhruvaraj Subhashchandran     size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
216*fef66a95SDhruvaraj Subhashchandran 
217*fef66a95SDhruvaraj Subhashchandran     if (size < BMC_DUMP_MIN_SPACE_REQD)
218*fef66a95SDhruvaraj Subhashchandran     {
219*fef66a95SDhruvaraj Subhashchandran         // Reached to maximum limit
220*fef66a95SDhruvaraj Subhashchandran         elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
221*fef66a95SDhruvaraj Subhashchandran     }
222*fef66a95SDhruvaraj Subhashchandran     if (size > BMC_DUMP_MAX_SIZE)
223*fef66a95SDhruvaraj Subhashchandran     {
224*fef66a95SDhruvaraj Subhashchandran         size = BMC_DUMP_MAX_SIZE;
225*fef66a95SDhruvaraj Subhashchandran     }
226*fef66a95SDhruvaraj Subhashchandran 
227*fef66a95SDhruvaraj Subhashchandran     return size;
228*fef66a95SDhruvaraj Subhashchandran }
229*fef66a95SDhruvaraj Subhashchandran 
230*fef66a95SDhruvaraj Subhashchandran } // namespace bmc
231*fef66a95SDhruvaraj Subhashchandran } // namespace dump
232*fef66a95SDhruvaraj Subhashchandran } // namespace phosphor
233