blob: 931c0eb5f145835f7e28b7f730f8a3daaa2acada [file] [log] [blame]
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -05001#include "config.h"
2
3#include "dump_manager_bmc.hpp"
4
5#include "bmc_dump_entry.hpp"
6#include "dump_internal.hpp"
7#include "xyz/openbmc_project/Common/error.hpp"
8#include "xyz/openbmc_project/Dump/Create/error.hpp"
9
10#include <sys/inotify.h>
11#include <unistd.h>
12
13#include <phosphor-logging/elog-errors.hpp>
14#include <phosphor-logging/elog.hpp>
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050015
16#include <ctime>
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050017#include <regex>
18
19namespace phosphor
20{
21namespace dump
22{
23namespace bmc
24{
25
26using namespace sdbusplus::xyz::openbmc_project::Common::Error;
27using namespace phosphor::logging;
28
29namespace internal
30{
31
32void Manager::create(Type type, std::vector<std::string> fullPaths)
33{
34 dumpMgr.phosphor::dump::bmc::Manager::captureDump(type, fullPaths);
35}
36
37} // namespace internal
38
Dhruvaraj Subhashchandran969f9a52020-10-30 01:42:39 -050039sdbusplus::message::object_path
40 Manager::createDump(std::map<std::string, std::string> params)
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050041{
Dhruvaraj Subhashchandran969f9a52020-10-30 01:42:39 -050042 if (!params.empty())
43 {
44 log<level::WARNING>("BMC dump accepts no additional parameters");
45 }
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050046 std::vector<std::string> paths;
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050047 auto id = captureDump(Type::UserRequested, paths);
48
49 // Entry Object path.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -050050 auto objPath = std::filesystem::path(baseEntryPath) / std::to_string(id);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050051
52 try
53 {
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050054 std::time_t timeStamp = std::time(nullptr);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050055 entries.insert(std::make_pair(
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050056 id, std::make_unique<bmc::Entry>(
57 bus, objPath.c_str(), id, timeStamp, 0, std::string(),
58 phosphor::dump::OperationStatus::InProgress, *this)));
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050059 }
60 catch (const std::invalid_argument& e)
61 {
62 log<level::ERR>(e.what());
63 log<level::ERR>("Error in creating dump entry",
64 entry("OBJECTPATH=%s", objPath.c_str()),
65 entry("ID=%d", id));
66 elog<InternalFailure>();
67 }
68
69 return objPath.string();
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050070}
71
72uint32_t Manager::captureDump(Type type,
73 const std::vector<std::string>& fullPaths)
74{
75 // Get Dump size.
76 auto size = getAllowedSize();
77
78 pid_t pid = fork();
79
80 if (pid == 0)
81 {
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -050082 std::filesystem::path dumpPath(dumpDir);
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050083 auto id = std::to_string(lastEntryId + 1);
84 dumpPath /= id;
85
86 // get dreport type map entry
87 auto tempType = TypeMap.find(type);
88
89 execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
90 id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
91 fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
92 tempType->second.c_str(), nullptr);
93
94 // dreport script execution is failed.
95 auto error = errno;
96 log<level::ERR>("Error occurred during dreport function execution",
97 entry("ERRNO=%d", error));
98 elog<InternalFailure>();
99 }
100 else if (pid > 0)
101 {
102 auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
103 WEXITED | WSTOPPED, callback, nullptr);
104 if (0 > rc)
105 {
106 // Failed to add to event loop
107 log<level::ERR>("Error occurred during the sd_event_add_child call",
108 entry("RC=%d", rc));
109 elog<InternalFailure>();
110 }
111 }
112 else
113 {
114 auto error = errno;
115 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
116 elog<InternalFailure>();
117 }
118
119 return ++lastEntryId;
120}
121
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500122void Manager::createEntry(const std::filesystem::path& file)
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500123{
124 // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
125 static constexpr auto ID_POS = 1;
126 static constexpr auto EPOCHTIME_POS = 2;
127 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
128
129 std::smatch match;
130 std::string name = file.filename();
131
132 if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
133 {
134 log<level::ERR>("Invalid Dump file name",
135 entry("FILENAME=%s", file.filename().c_str()));
136 return;
137 }
138
139 auto idString = match[ID_POS];
140 auto msString = match[EPOCHTIME_POS];
141
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500142 auto id = stoul(idString);
143
144 // If there is an existing entry update it and return.
145 auto dumpEntry = entries.find(id);
146 if (dumpEntry != entries.end())
147 {
148 dynamic_cast<phosphor::dump::bmc::Entry*>(dumpEntry->second.get())
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500149 ->update(stoull(msString), std::filesystem::file_size(file), file);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500150 return;
151 }
152
153 // Entry Object path.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500154 auto objPath = std::filesystem::path(baseEntryPath) / std::to_string(id);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500155
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500156 try
157 {
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -0500158 entries.insert(std::make_pair(
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500159 id, std::make_unique<bmc::Entry>(
160 bus, objPath.c_str(), id, stoull(msString),
161 std::filesystem::file_size(file), file,
162 phosphor::dump::OperationStatus::Completed, *this)));
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500163 }
164 catch (const std::invalid_argument& e)
165 {
166 log<level::ERR>(e.what());
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500167 log<level::ERR>("Error in creating dump entry",
168 entry("OBJECTPATH=%s", objPath.c_str()),
169 entry("ID=%d", id),
170 entry("TIMESTAMP=%ull", stoull(msString)),
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500171 entry("SIZE=%d", std::filesystem::file_size(file)),
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500172 entry("FILENAME=%s", file.c_str()));
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500173 return;
174 }
175}
176
177void Manager::watchCallback(const UserMap& fileInfo)
178{
179 for (const auto& i : fileInfo)
180 {
181 // For any new dump file create dump entry object
182 // and associated inotify watch.
183 if (IN_CLOSE_WRITE == i.second)
184 {
185 removeWatch(i.first);
186
187 createEntry(i.first);
188 }
189 // Start inotify watch on newly created directory.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500190 else if ((IN_CREATE == i.second) &&
191 std::filesystem::is_directory(i.first))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500192 {
193 auto watchObj = std::make_unique<Watch>(
194 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
195 std::bind(
196 std::mem_fn(&phosphor::dump::bmc::Manager::watchCallback),
197 this, std::placeholders::_1));
198
199 childWatchMap.emplace(i.first, std::move(watchObj));
200 }
201 }
202}
203
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500204void Manager::removeWatch(const std::filesystem::path& path)
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500205{
206 // Delete Watch entry from map.
207 childWatchMap.erase(path);
208}
209
210void Manager::restore()
211{
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500212 std::filesystem::path dir(dumpDir);
213 if (!std::filesystem::exists(dir) || std::filesystem::is_empty(dir))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500214 {
215 return;
216 }
217
218 // Dump file path: <DUMP_PATH>/<id>/<filename>
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500219 for (const auto& p : std::filesystem::directory_iterator(dir))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500220 {
221 auto idStr = p.path().filename().string();
222
223 // Consider only directory's with dump id as name.
224 // Note: As per design one file per directory.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500225 if ((std::filesystem::is_directory(p.path())) &&
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500226 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
227 {
228 lastEntryId =
229 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500230 auto fileIt = std::filesystem::directory_iterator(p.path());
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500231 // Create dump entry d-bus object.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500232 if (fileIt != std::filesystem::end(fileIt))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500233 {
234 createEntry(fileIt->path());
235 }
236 }
237 }
238}
239
240size_t Manager::getAllowedSize()
241{
242 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
243 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
244
245 auto size = 0;
246
247 // Get current size of the dump directory.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500248 for (const auto& p : std::filesystem::recursive_directory_iterator(dumpDir))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500249 {
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500250 if (!std::filesystem::is_directory(p))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500251 {
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500252 size += std::filesystem::file_size(p);
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500253 }
254 }
255
256 // Convert size into KB
257 size = size / 1024;
258
259 // Set the Dump size to Maximum if the free space is greater than
260 // Dump max size otherwise return the available size.
261
262 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
263
264 if (size < BMC_DUMP_MIN_SPACE_REQD)
265 {
266 // Reached to maximum limit
267 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
268 }
269 if (size > BMC_DUMP_MAX_SIZE)
270 {
271 size = BMC_DUMP_MAX_SIZE;
272 }
273
274 return size;
275}
276
277} // namespace bmc
278} // namespace dump
279} // namespace phosphor