blob: 4d0904c8a054d62fdc13e346920e795da245de54 [file] [log] [blame]
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05001#include <unistd.h>
Jayanth Othayothbcb174b2017-07-02 06:29:24 -05002#include <sys/inotify.h>
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -05003#include <regex>
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05004
Jayanth Othayothab7f9202017-08-02 06:24:58 -05005#include <phosphor-logging/elog.hpp>
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05006#include <phosphor-logging/elog-errors.hpp>
7
8#include "dump_manager.hpp"
9#include "dump_internal.hpp"
10#include "xyz/openbmc_project/Common/error.hpp"
Jayanth Othayothab7f9202017-08-02 06:24:58 -050011#include "xyz/openbmc_project/Dump/Create/error.hpp"
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050012#include "config.h"
13
14namespace phosphor
15{
16namespace dump
17{
18
19using namespace sdbusplus::xyz::openbmc_project::Common::Error;
20using namespace phosphor::logging;
21
22namespace internal
23{
24
25void Manager::create(
26 Type type,
27 std::vector<std::string> fullPaths)
28{
Jayanth Othayothd3273ea2017-07-12 22:55:32 -050029 dumpMgr.phosphor::dump::Manager::captureDump(type, fullPaths);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050030}
31
32} //namepsace internal
33
34uint32_t Manager::createDump()
35{
36 std::vector<std::string> paths;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050037 return captureDump(Type::UserRequested, paths);
38}
39
40uint32_t Manager::captureDump(
41 Type type,
42 const std::vector<std::string>& fullPaths)
43{
Jayanth Othayoth9c155582017-08-09 07:47:45 -050044 //Type to dreport type string map
45 static const std::map<Type, std::string> typeMap =
46 {{Type::ApplicationCored, "core"},
Jayanth Othayothd0f00642017-09-04 06:26:30 -050047 {Type::UserRequested, "user"},
48 {Type::InternalFailure, "elog"}};
Jayanth Othayoth9c155582017-08-09 07:47:45 -050049
50 //Get Dump size.
51 auto size = getAllowedSize();
52
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050053 pid_t pid = fork();
54
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050055 if (pid == 0)
56 {
Jayanth Othayothf9009a22017-07-12 19:40:34 -050057 fs::path dumpPath(BMC_DUMP_PATH);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050058 auto id = std::to_string(lastEntryId + 1);
59 dumpPath /= id;
Jayanth Othayothf9009a22017-07-12 19:40:34 -050060
Jayanth Othayoth9c155582017-08-09 07:47:45 -050061 //get dreport type map entry
62 auto tempType = typeMap.find(type);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050063
Jayanth Othayoth9c155582017-08-09 07:47:45 -050064 execl("/usr/bin/dreport",
65 "dreport",
66 "-d", dumpPath.c_str(),
67 "-i", id.c_str(),
68 "-s", std::to_string(size).c_str(),
69 "-q",
70 "-v",
Jayanth Othayothd44513c2017-09-04 01:17:07 -050071 "-p", fullPaths.empty() ? "" : fullPaths.front().c_str(),
Jayanth Othayoth9c155582017-08-09 07:47:45 -050072 "-t", tempType->second.c_str(),
73 nullptr);
74
75 //dreport script execution is failed.
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050076 auto error = errno;
Jayanth Othayoth9c155582017-08-09 07:47:45 -050077 log<level::ERR>("Error occurred during dreport function execution",
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050078 entry("ERRNO=%d", error));
79 elog<InternalFailure>();
80 }
81 else if (pid > 0)
82 {
83 auto rc = sd_event_add_child(eventLoop.get(),
84 nullptr,
85 pid,
86 WEXITED | WSTOPPED,
87 callback,
88 nullptr);
89 if (0 > rc)
90 {
91 // Failed to add to event loop
92 log<level::ERR>("Error occurred during the sd_event_add_child call",
Gunnar Mills11eaab72017-10-19 16:07:31 -050093 entry("RC=%d", rc));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050094 elog<InternalFailure>();
95 }
96 }
97 else
98 {
99 auto error = errno;
100 log<level::ERR>("Error occurred during fork",
101 entry("ERRNO=%d", error));
102 elog<InternalFailure>();
103 }
104
105 return ++lastEntryId;
106}
107
108void Manager::createEntry(const fs::path& file)
109{
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500110 //Dump File Name format obmcdump_ID_EPOCHTIME.EXT
111 static constexpr auto ID_POS = 1;
112 static constexpr auto EPOCHTIME_POS = 2;
113 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500114
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500115 std::smatch match;
116 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500117
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500118 if (!((std::regex_search(name, match, file_regex)) &&
119 (match.size() > 0)))
120 {
121 log<level::ERR>("Invalid Dump file name",
Gunnar Mills11eaab72017-10-19 16:07:31 -0500122 entry("FILENAME=%s", file.filename()));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500123 return;
124 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500125
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500126 auto idString = match[ID_POS];
127 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500128
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500129 try
130 {
131 auto id = stoul(idString);
132 // Entry Object path.
133 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
134
135 entries.insert(std::make_pair(id,
136 std::make_unique<Entry>(
137 bus,
138 objPath.c_str(),
139 id,
140 stoull(msString),
141 fs::file_size(file),
142 file,
143 *this)));
144 }
145 catch (const std::invalid_argument& e)
146 {
147 log<level::ERR>(e.what());
148 return;
149 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500150}
151
152void Manager::erase(uint32_t entryId)
153{
154 entries.erase(entryId);
155}
156
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500157void Manager::deleteAll()
158{
159 auto iter = entries.begin();
160 while (iter != entries.end())
161 {
162 auto& entry = iter->second;
163 entry->delete_();
164 ++iter;
165 }
166}
167
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500168void Manager::watchCallback(const UserMap& fileInfo)
169{
170 for (const auto& i : fileInfo)
171 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500172 // For any new dump file create dump entry object
173 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500174 if (IN_CLOSE_WRITE == i.second)
175 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500176 removeWatch(i.first);
177
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500178 createEntry(i.first);
179 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500180 // Start inotify watch on newly created directory.
181 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
182 {
183 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500184 eventLoop,
185 IN_NONBLOCK,
186 IN_CLOSE_WRITE,
187 EPOLLIN,
188 i.first,
189 std::bind(
190 std::mem_fn(
191 &phosphor::dump::Manager::watchCallback),
192 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500193
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500194 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500195 }
196
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500197 }
198}
199
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500200void Manager::removeWatch(const fs::path& path)
201{
202 //Delete Watch entry from map.
203 childWatchMap.erase(path);
204}
205
Jayanth Othayoth43096592017-07-20 02:17:37 -0500206void Manager::restore()
207{
208 fs::path dir(BMC_DUMP_PATH);
209 if (!fs::exists(dir) || fs::is_empty(dir))
210 {
211 return;
212 }
213
214 //Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
215 for (const auto& p : fs::directory_iterator(dir))
216 {
217 auto idStr = p.path().filename().string();
218
219 //Consider only directory's with dump id as name.
220 //Note: As per design one file per directory.
221 if ((fs::is_directory(p.path())) &&
222 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
223 {
224 lastEntryId = std::max(lastEntryId,
225 static_cast<uint32_t>(std::stoul(idStr)));
226 auto fileIt = fs::directory_iterator(p.path());
227 //Create dump entry d-bus object.
228 if (fileIt != fs::end(fileIt))
229 {
230 createEntry(fileIt->path());
231 }
232 }
233 }
234}
235
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500236size_t Manager::getAllowedSize()
237{
238 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
239 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
240
241 auto size = 0;
242
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500243 //Get current size of the dump directory.
244 for (const auto& p : fs::recursive_directory_iterator(BMC_DUMP_PATH))
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500245 {
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500246 if (!fs::is_directory(p))
247 {
248 size += fs::file_size(p);
249 }
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500250 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500251
252 //Convert size into KB
253 size = size / 1024;
254
255 //Set the Dump size to Maximum if the free space is greater than
256 //Dump max size otherwise return the available size.
257
258 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
259
260 if (size < BMC_DUMP_MIN_SPACE_REQD)
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500261 {
262 //Reached to maximum limit
263 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
264 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500265 if (size > BMC_DUMP_MAX_SIZE)
266 {
267 size = BMC_DUMP_MAX_SIZE;
268 }
269
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500270 return size;
271}
272
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500273} //namespace dump
274} //namespace phosphor