blob: 040c8ccdef0705ae9fe567598435d59ae77f9a54 [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"},
47 {Type::UserRequested, "user"}};
48
49 //Get Dump size.
50 auto size = getAllowedSize();
51
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050052 pid_t pid = fork();
53
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050054 if (pid == 0)
55 {
Jayanth Othayothf9009a22017-07-12 19:40:34 -050056 fs::path dumpPath(BMC_DUMP_PATH);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050057 auto id = std::to_string(lastEntryId + 1);
58 dumpPath /= id;
Jayanth Othayothf9009a22017-07-12 19:40:34 -050059
Jayanth Othayoth9c155582017-08-09 07:47:45 -050060 //get dreport type map entry
61 auto tempType = typeMap.find(type);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050062
Jayanth Othayoth9c155582017-08-09 07:47:45 -050063 execl("/usr/bin/dreport",
64 "dreport",
65 "-d", dumpPath.c_str(),
66 "-i", id.c_str(),
67 "-s", std::to_string(size).c_str(),
68 "-q",
69 "-v",
Jayanth Othayoth217fb5f2017-08-26 01:45:31 -050070 "-f", fullPaths.empty() ? "" : fullPaths.front().c_str(),
Jayanth Othayoth9c155582017-08-09 07:47:45 -050071 "-t", tempType->second.c_str(),
72 nullptr);
73
74 //dreport script execution is failed.
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050075 auto error = errno;
Jayanth Othayoth9c155582017-08-09 07:47:45 -050076 log<level::ERR>("Error occurred during dreport function execution",
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050077 entry("ERRNO=%d", error));
78 elog<InternalFailure>();
79 }
80 else if (pid > 0)
81 {
82 auto rc = sd_event_add_child(eventLoop.get(),
83 nullptr,
84 pid,
85 WEXITED | WSTOPPED,
86 callback,
87 nullptr);
88 if (0 > rc)
89 {
90 // Failed to add to event loop
91 log<level::ERR>("Error occurred during the sd_event_add_child call",
92 entry("rc=%d", rc));
93 elog<InternalFailure>();
94 }
95 }
96 else
97 {
98 auto error = errno;
99 log<level::ERR>("Error occurred during fork",
100 entry("ERRNO=%d", error));
101 elog<InternalFailure>();
102 }
103
104 return ++lastEntryId;
105}
106
107void Manager::createEntry(const fs::path& file)
108{
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500109 //Dump File Name format obmcdump_ID_EPOCHTIME.EXT
110 static constexpr auto ID_POS = 1;
111 static constexpr auto EPOCHTIME_POS = 2;
112 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500113
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500114 std::smatch match;
115 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500116
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500117 if (!((std::regex_search(name, match, file_regex)) &&
118 (match.size() > 0)))
119 {
120 log<level::ERR>("Invalid Dump file name",
121 entry("Filename=%s", file.filename()));
122 return;
123 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500124
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500125 auto idString = match[ID_POS];
126 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500127
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500128 try
129 {
130 auto id = stoul(idString);
131 // Entry Object path.
132 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
133
134 entries.insert(std::make_pair(id,
135 std::make_unique<Entry>(
136 bus,
137 objPath.c_str(),
138 id,
139 stoull(msString),
140 fs::file_size(file),
141 file,
142 *this)));
143 }
144 catch (const std::invalid_argument& e)
145 {
146 log<level::ERR>(e.what());
147 return;
148 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500149}
150
151void Manager::erase(uint32_t entryId)
152{
153 entries.erase(entryId);
154}
155
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500156void Manager::watchCallback(const UserMap& fileInfo)
157{
158 for (const auto& i : fileInfo)
159 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500160 // For any new dump file create dump entry object
161 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500162 if (IN_CLOSE_WRITE == i.second)
163 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500164 removeWatch(i.first);
165
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500166 createEntry(i.first);
167 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500168 // Start inotify watch on newly created directory.
169 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
170 {
171 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500172 eventLoop,
173 IN_NONBLOCK,
174 IN_CLOSE_WRITE,
175 EPOLLIN,
176 i.first,
177 std::bind(
178 std::mem_fn(
179 &phosphor::dump::Manager::watchCallback),
180 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500181
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500182 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500183 }
184
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500185 }
186}
187
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500188void Manager::removeWatch(const fs::path& path)
189{
190 //Delete Watch entry from map.
191 childWatchMap.erase(path);
192}
193
Jayanth Othayoth43096592017-07-20 02:17:37 -0500194void Manager::restore()
195{
196 fs::path dir(BMC_DUMP_PATH);
197 if (!fs::exists(dir) || fs::is_empty(dir))
198 {
199 return;
200 }
201
202 //Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
203 for (const auto& p : fs::directory_iterator(dir))
204 {
205 auto idStr = p.path().filename().string();
206
207 //Consider only directory's with dump id as name.
208 //Note: As per design one file per directory.
209 if ((fs::is_directory(p.path())) &&
210 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
211 {
212 lastEntryId = std::max(lastEntryId,
213 static_cast<uint32_t>(std::stoul(idStr)));
214 auto fileIt = fs::directory_iterator(p.path());
215 //Create dump entry d-bus object.
216 if (fileIt != fs::end(fileIt))
217 {
218 createEntry(fileIt->path());
219 }
220 }
221 }
222}
223
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500224size_t Manager::getAllowedSize()
225{
226 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
227 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
228
229 auto size = 0;
230
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500231 //Get current size of the dump directory.
232 for (const auto& p : fs::recursive_directory_iterator(BMC_DUMP_PATH))
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500233 {
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500234 if (!fs::is_directory(p))
235 {
236 size += fs::file_size(p);
237 }
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500238 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500239
240 //Convert size into KB
241 size = size / 1024;
242
243 //Set the Dump size to Maximum if the free space is greater than
244 //Dump max size otherwise return the available size.
245
246 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
247
248 if (size < BMC_DUMP_MIN_SPACE_REQD)
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500249 {
250 //Reached to maximum limit
251 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
252 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500253 if (size > BMC_DUMP_MAX_SIZE)
254 {
255 size = BMC_DUMP_MAX_SIZE;
256 }
257
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500258 return size;
259}
260
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500261} //namespace dump
262} //namespace phosphor