blob: f5701816ea8fdd0b88eff8f6fa7316e501ad5f91 [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
Tim Leebb9366d2021-06-24 14:00:07 +080016#include <cmath>
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050017#include <ctime>
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050018#include <regex>
19
20namespace phosphor
21{
22namespace dump
23{
24namespace bmc
25{
26
27using namespace sdbusplus::xyz::openbmc_project::Common::Error;
28using namespace phosphor::logging;
29
30namespace internal
31{
32
33void Manager::create(Type type, std::vector<std::string> fullPaths)
34{
35 dumpMgr.phosphor::dump::bmc::Manager::captureDump(type, fullPaths);
36}
37
38} // namespace internal
39
Dhruvaraj Subhashchandran969f9a52020-10-30 01:42:39 -050040sdbusplus::message::object_path
41 Manager::createDump(std::map<std::string, std::string> params)
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050042{
Dhruvaraj Subhashchandran969f9a52020-10-30 01:42:39 -050043 if (!params.empty())
44 {
45 log<level::WARNING>("BMC dump accepts no additional parameters");
46 }
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050047 std::vector<std::string> paths;
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050048 auto id = captureDump(Type::UserRequested, paths);
49
50 // Entry Object path.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -050051 auto objPath = std::filesystem::path(baseEntryPath) / std::to_string(id);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050052
53 try
54 {
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050055 std::time_t timeStamp = std::time(nullptr);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050056 entries.insert(std::make_pair(
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050057 id, std::make_unique<bmc::Entry>(
58 bus, objPath.c_str(), id, timeStamp, 0, std::string(),
59 phosphor::dump::OperationStatus::InProgress, *this)));
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050060 }
61 catch (const std::invalid_argument& e)
62 {
63 log<level::ERR>(e.what());
64 log<level::ERR>("Error in creating dump entry",
65 entry("OBJECTPATH=%s", objPath.c_str()),
66 entry("ID=%d", id));
67 elog<InternalFailure>();
68 }
69
70 return objPath.string();
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050071}
72
73uint32_t Manager::captureDump(Type type,
74 const std::vector<std::string>& fullPaths)
75{
76 // Get Dump size.
77 auto size = getAllowedSize();
78
79 pid_t pid = fork();
80
81 if (pid == 0)
82 {
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -050083 std::filesystem::path dumpPath(dumpDir);
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050084 auto id = std::to_string(lastEntryId + 1);
85 dumpPath /= id;
86
87 // get dreport type map entry
88 auto tempType = TypeMap.find(type);
89
90 execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
91 id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
92 fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
93 tempType->second.c_str(), nullptr);
94
95 // dreport script execution is failed.
96 auto error = errno;
97 log<level::ERR>("Error occurred during dreport function execution",
98 entry("ERRNO=%d", error));
99 elog<InternalFailure>();
100 }
101 else if (pid > 0)
102 {
103 auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
104 WEXITED | WSTOPPED, callback, nullptr);
105 if (0 > rc)
106 {
107 // Failed to add to event loop
108 log<level::ERR>("Error occurred during the sd_event_add_child call",
109 entry("RC=%d", rc));
110 elog<InternalFailure>();
111 }
112 }
113 else
114 {
115 auto error = errno;
116 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
117 elog<InternalFailure>();
118 }
119
120 return ++lastEntryId;
121}
122
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500123void Manager::createEntry(const std::filesystem::path& file)
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500124{
125 // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
126 static constexpr auto ID_POS = 1;
127 static constexpr auto EPOCHTIME_POS = 2;
128 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
129
130 std::smatch match;
131 std::string name = file.filename();
132
133 if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
134 {
135 log<level::ERR>("Invalid Dump file name",
136 entry("FILENAME=%s", file.filename().c_str()));
137 return;
138 }
139
140 auto idString = match[ID_POS];
141 auto msString = match[EPOCHTIME_POS];
142
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500143 auto id = stoul(idString);
144
145 // If there is an existing entry update it and return.
146 auto dumpEntry = entries.find(id);
147 if (dumpEntry != entries.end())
148 {
149 dynamic_cast<phosphor::dump::bmc::Entry*>(dumpEntry->second.get())
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500150 ->update(stoull(msString), std::filesystem::file_size(file), file);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500151 return;
152 }
153
154 // Entry Object path.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500155 auto objPath = std::filesystem::path(baseEntryPath) / std::to_string(id);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500156
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500157 try
158 {
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -0500159 entries.insert(std::make_pair(
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500160 id, std::make_unique<bmc::Entry>(
161 bus, objPath.c_str(), id, stoull(msString),
162 std::filesystem::file_size(file), file,
163 phosphor::dump::OperationStatus::Completed, *this)));
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500164 }
165 catch (const std::invalid_argument& e)
166 {
167 log<level::ERR>(e.what());
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500168 log<level::ERR>("Error in creating dump entry",
169 entry("OBJECTPATH=%s", objPath.c_str()),
170 entry("ID=%d", id),
171 entry("TIMESTAMP=%ull", stoull(msString)),
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500172 entry("SIZE=%d", std::filesystem::file_size(file)),
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500173 entry("FILENAME=%s", file.c_str()));
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500174 return;
175 }
176}
177
178void Manager::watchCallback(const UserMap& fileInfo)
179{
180 for (const auto& i : fileInfo)
181 {
182 // For any new dump file create dump entry object
183 // and associated inotify watch.
184 if (IN_CLOSE_WRITE == i.second)
185 {
186 removeWatch(i.first);
187
188 createEntry(i.first);
189 }
190 // Start inotify watch on newly created directory.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500191 else if ((IN_CREATE == i.second) &&
192 std::filesystem::is_directory(i.first))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500193 {
194 auto watchObj = std::make_unique<Watch>(
195 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
196 std::bind(
197 std::mem_fn(&phosphor::dump::bmc::Manager::watchCallback),
198 this, std::placeholders::_1));
199
200 childWatchMap.emplace(i.first, std::move(watchObj));
201 }
202 }
203}
204
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500205void Manager::removeWatch(const std::filesystem::path& path)
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500206{
207 // Delete Watch entry from map.
208 childWatchMap.erase(path);
209}
210
211void Manager::restore()
212{
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500213 std::filesystem::path dir(dumpDir);
214 if (!std::filesystem::exists(dir) || std::filesystem::is_empty(dir))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500215 {
216 return;
217 }
218
219 // Dump file path: <DUMP_PATH>/<id>/<filename>
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500220 for (const auto& p : std::filesystem::directory_iterator(dir))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500221 {
222 auto idStr = p.path().filename().string();
223
224 // Consider only directory's with dump id as name.
225 // Note: As per design one file per directory.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500226 if ((std::filesystem::is_directory(p.path())) &&
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500227 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
228 {
229 lastEntryId =
230 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500231 auto fileIt = std::filesystem::directory_iterator(p.path());
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500232 // Create dump entry d-bus object.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500233 if (fileIt != std::filesystem::end(fileIt))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500234 {
235 createEntry(fileIt->path());
236 }
237 }
238 }
239}
240
241size_t Manager::getAllowedSize()
242{
243 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
244 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
245
246 auto size = 0;
247
248 // Get current size of the dump directory.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500249 for (const auto& p : std::filesystem::recursive_directory_iterator(dumpDir))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500250 {
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500251 if (!std::filesystem::is_directory(p))
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500252 {
Tim Leebb9366d2021-06-24 14:00:07 +0800253 size += std::ceil(std::filesystem::file_size(p) / 1024.0);
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500254 }
255 }
256
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500257 // Set the Dump size to Maximum if the free space is greater than
258 // Dump max size otherwise return the available size.
259
260 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
261
262 if (size < BMC_DUMP_MIN_SPACE_REQD)
263 {
264 // Reached to maximum limit
265 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
266 }
267 if (size > BMC_DUMP_MAX_SIZE)
268 {
269 size = BMC_DUMP_MAX_SIZE;
270 }
271
272 return size;
273}
274
275} // namespace bmc
276} // namespace dump
277} // namespace phosphor