blob: 0236e468d453ba6f6a3e4e81646efb7681bdce46 [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
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050013#include <ctime>
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050014#include <phosphor-logging/elog-errors.hpp>
15#include <phosphor-logging/elog.hpp>
16#include <regex>
17
18namespace phosphor
19{
20namespace dump
21{
22namespace bmc
23{
24
25using namespace sdbusplus::xyz::openbmc_project::Common::Error;
26using namespace phosphor::logging;
27
28namespace internal
29{
30
31void Manager::create(Type type, std::vector<std::string> fullPaths)
32{
33 dumpMgr.phosphor::dump::bmc::Manager::captureDump(type, fullPaths);
34}
35
36} // namespace internal
37
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050038sdbusplus::message::object_path Manager::createDump()
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050039{
40 std::vector<std::string> paths;
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050041 auto id = captureDump(Type::UserRequested, paths);
42
43 // Entry Object path.
44 auto objPath = fs::path(baseEntryPath) / std::to_string(id);
45
46 try
47 {
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050048 std::time_t timeStamp = std::time(nullptr);
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050049 entries.insert(std::make_pair(
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -050050 id, std::make_unique<bmc::Entry>(
51 bus, objPath.c_str(), id, timeStamp, 0, std::string(),
52 phosphor::dump::OperationStatus::InProgress, *this)));
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -050053 }
54 catch (const std::invalid_argument& e)
55 {
56 log<level::ERR>(e.what());
57 log<level::ERR>("Error in creating dump entry",
58 entry("OBJECTPATH=%s", objPath.c_str()),
59 entry("ID=%d", id));
60 elog<InternalFailure>();
61 }
62
63 return objPath.string();
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -050064}
65
66uint32_t Manager::captureDump(Type type,
67 const std::vector<std::string>& fullPaths)
68{
69 // Get Dump size.
70 auto size = getAllowedSize();
71
72 pid_t pid = fork();
73
74 if (pid == 0)
75 {
76 fs::path dumpPath(dumpDir);
77 auto id = std::to_string(lastEntryId + 1);
78 dumpPath /= id;
79
80 // get dreport type map entry
81 auto tempType = TypeMap.find(type);
82
83 execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
84 id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
85 fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
86 tempType->second.c_str(), nullptr);
87
88 // dreport script execution is failed.
89 auto error = errno;
90 log<level::ERR>("Error occurred during dreport function execution",
91 entry("ERRNO=%d", error));
92 elog<InternalFailure>();
93 }
94 else if (pid > 0)
95 {
96 auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
97 WEXITED | WSTOPPED, callback, nullptr);
98 if (0 > rc)
99 {
100 // Failed to add to event loop
101 log<level::ERR>("Error occurred during the sd_event_add_child call",
102 entry("RC=%d", rc));
103 elog<InternalFailure>();
104 }
105 }
106 else
107 {
108 auto error = errno;
109 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
110 elog<InternalFailure>();
111 }
112
113 return ++lastEntryId;
114}
115
116void Manager::createEntry(const fs::path& file)
117{
118 // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
119 static constexpr auto ID_POS = 1;
120 static constexpr auto EPOCHTIME_POS = 2;
121 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
122
123 std::smatch match;
124 std::string name = file.filename();
125
126 if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
127 {
128 log<level::ERR>("Invalid Dump file name",
129 entry("FILENAME=%s", file.filename().c_str()));
130 return;
131 }
132
133 auto idString = match[ID_POS];
134 auto msString = match[EPOCHTIME_POS];
135
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500136 auto id = stoul(idString);
137
138 // If there is an existing entry update it and return.
139 auto dumpEntry = entries.find(id);
140 if (dumpEntry != entries.end())
141 {
142 dynamic_cast<phosphor::dump::bmc::Entry*>(dumpEntry->second.get())
143 ->update(stoull(msString), fs::file_size(file), file);
144 return;
145 }
146
147 // Entry Object path.
148 auto objPath = fs::path(baseEntryPath) / std::to_string(id);
149
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500150 try
151 {
Dhruvaraj Subhashchandrana6ab8062020-10-29 15:29:10 -0500152 entries.insert(std::make_pair(
153 id,
154 std::make_unique<bmc::Entry>(
155 bus, objPath.c_str(), id, stoull(msString), fs::file_size(file),
156 file, phosphor::dump::OperationStatus::Completed, *this)));
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500157 }
158 catch (const std::invalid_argument& e)
159 {
160 log<level::ERR>(e.what());
Dhruvaraj Subhashchandran6ccb50e2020-10-29 09:33:18 -0500161 log<level::ERR>("Error in creating dump entry",
162 entry("OBJECTPATH=%s", objPath.c_str()),
163 entry("ID=%d", id),
164 entry("TIMESTAMP=%ull", stoull(msString)),
165 entry("SIZE=%d", fs::file_size(file)),
166 entry("FILENAME=%s", file.c_str()));
Dhruvaraj Subhashchandranfef66a92020-09-06 13:10:59 -0500167 return;
168 }
169}
170
171void Manager::watchCallback(const UserMap& fileInfo)
172{
173 for (const auto& i : fileInfo)
174 {
175 // For any new dump file create dump entry object
176 // and associated inotify watch.
177 if (IN_CLOSE_WRITE == i.second)
178 {
179 removeWatch(i.first);
180
181 createEntry(i.first);
182 }
183 // Start inotify watch on newly created directory.
184 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
185 {
186 auto watchObj = std::make_unique<Watch>(
187 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
188 std::bind(
189 std::mem_fn(&phosphor::dump::bmc::Manager::watchCallback),
190 this, std::placeholders::_1));
191
192 childWatchMap.emplace(i.first, std::move(watchObj));
193 }
194 }
195}
196
197void Manager::removeWatch(const fs::path& path)
198{
199 // Delete Watch entry from map.
200 childWatchMap.erase(path);
201}
202
203void Manager::restore()
204{
205 fs::path dir(dumpDir);
206 if (!fs::exists(dir) || fs::is_empty(dir))
207 {
208 return;
209 }
210
211 // Dump file path: <DUMP_PATH>/<id>/<filename>
212 for (const auto& p : fs::directory_iterator(dir))
213 {
214 auto idStr = p.path().filename().string();
215
216 // Consider only directory's with dump id as name.
217 // Note: As per design one file per directory.
218 if ((fs::is_directory(p.path())) &&
219 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
220 {
221 lastEntryId =
222 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
223 auto fileIt = fs::directory_iterator(p.path());
224 // Create dump entry d-bus object.
225 if (fileIt != fs::end(fileIt))
226 {
227 createEntry(fileIt->path());
228 }
229 }
230 }
231}
232
233size_t Manager::getAllowedSize()
234{
235 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
236 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
237
238 auto size = 0;
239
240 // Get current size of the dump directory.
241 for (const auto& p : fs::recursive_directory_iterator(dumpDir))
242 {
243 if (!fs::is_directory(p))
244 {
245 size += fs::file_size(p);
246 }
247 }
248
249 // Convert size into KB
250 size = size / 1024;
251
252 // Set the Dump size to Maximum if the free space is greater than
253 // Dump max size otherwise return the available size.
254
255 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
256
257 if (size < BMC_DUMP_MIN_SPACE_REQD)
258 {
259 // Reached to maximum limit
260 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
261 }
262 if (size > BMC_DUMP_MAX_SIZE)
263 {
264 size = BMC_DUMP_MAX_SIZE;
265 }
266
267 return size;
268}
269
270} // namespace bmc
271} // namespace dump
272} // namespace phosphor