blob: d9326e0f0f90d31ac73d0767d2190ec31af23f58 [file] [log] [blame]
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05001#include "config.h"
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05002
3#include "dump_manager.hpp"
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05004
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05005#include "dump_internal.hpp"
6#include "xyz/openbmc_project/Common/error.hpp"
Jayanth Othayothab7f9202017-08-02 06:24:58 -05007#include "xyz/openbmc_project/Dump/Create/error.hpp"
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05008
9#include <sys/inotify.h>
10#include <unistd.h>
11
12#include <phosphor-logging/elog-errors.hpp>
13#include <phosphor-logging/elog.hpp>
14#include <regex>
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050015
16namespace phosphor
17{
18namespace dump
19{
20
21using namespace sdbusplus::xyz::openbmc_project::Common::Error;
22using namespace phosphor::logging;
23
24namespace internal
25{
26
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050027void Manager::create(Type type, std::vector<std::string> fullPaths)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050028{
Jayanth Othayothd3273ea2017-07-12 22:55:32 -050029 dumpMgr.phosphor::dump::Manager::captureDump(type, fullPaths);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050030}
31
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050032} // namespace internal
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050033
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
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050040uint32_t Manager::captureDump(Type type,
41 const std::vector<std::string>& fullPaths)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050042{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050043 // Type to dreport type string map
44 static const std::map<Type, std::string> typeMap = {
45 {Type::ApplicationCored, "core"},
46 {Type::UserRequested, "user"},
47 {Type::InternalFailure, "elog"}};
Jayanth Othayoth9c155582017-08-09 07:47:45 -050048
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050049 // Get Dump size.
Jayanth Othayoth9c155582017-08-09 07:47:45 -050050 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 Othayothcb65ffc2018-10-16 08:29:32 -050057 auto id = std::to_string(lastEntryId + 1);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050058 dumpPath /= id;
Jayanth Othayothf9009a22017-07-12 19:40:34 -050059
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050060 // get dreport type map entry
Jayanth Othayoth9c155582017-08-09 07:47:45 -050061 auto tempType = typeMap.find(type);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050062
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050063 execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
64 id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
65 fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
66 tempType->second.c_str(), nullptr);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050067
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050068 // dreport script execution is failed.
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050069 auto error = errno;
Jayanth Othayoth9c155582017-08-09 07:47:45 -050070 log<level::ERR>("Error occurred during dreport function execution",
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050071 entry("ERRNO=%d", error));
72 elog<InternalFailure>();
73 }
74 else if (pid > 0)
75 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050076 auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
77 WEXITED | WSTOPPED, callback, nullptr);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050078 if (0 > rc)
79 {
80 // Failed to add to event loop
81 log<level::ERR>("Error occurred during the sd_event_add_child call",
Gunnar Mills11eaab72017-10-19 16:07:31 -050082 entry("RC=%d", rc));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050083 elog<InternalFailure>();
84 }
85 }
86 else
87 {
88 auto error = errno;
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050089 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050090 elog<InternalFailure>();
91 }
92
93 return ++lastEntryId;
94}
95
96void Manager::createEntry(const fs::path& file)
97{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050098 // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
99 static constexpr auto ID_POS = 1;
100 static constexpr auto EPOCHTIME_POS = 2;
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500101 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500102
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500103 std::smatch match;
104 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500105
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500106 if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500107 {
108 log<level::ERR>("Invalid Dump file name",
Joseph Reynoldsaf487622018-05-10 15:54:16 -0500109 entry("FILENAME=%s", file.filename().c_str()));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500110 return;
111 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500112
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500113 auto idString = match[ID_POS];
114 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500115
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500116 try
117 {
118 auto id = stoul(idString);
119 // Entry Object path.
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500120 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500121
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500122 entries.insert(std::make_pair(
123 id,
124 std::make_unique<Entry>(bus, objPath.c_str(), id, stoull(msString),
125 fs::file_size(file), file, *this)));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500126 }
127 catch (const std::invalid_argument& e)
128 {
129 log<level::ERR>(e.what());
130 return;
131 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500132}
133
134void Manager::erase(uint32_t entryId)
135{
136 entries.erase(entryId);
137}
138
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500139void Manager::deleteAll()
140{
141 auto iter = entries.begin();
142 while (iter != entries.end())
143 {
144 auto& entry = iter->second;
145 entry->delete_();
146 ++iter;
147 }
148}
149
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500150void Manager::watchCallback(const UserMap& fileInfo)
151{
152 for (const auto& i : fileInfo)
153 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500154 // For any new dump file create dump entry object
155 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500156 if (IN_CLOSE_WRITE == i.second)
157 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500158 removeWatch(i.first);
159
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500160 createEntry(i.first);
161 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500162 // Start inotify watch on newly created directory.
163 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
164 {
165 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500166 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
167 std::bind(std::mem_fn(&phosphor::dump::Manager::watchCallback),
168 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500169
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500170 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500171 }
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500172 }
173}
174
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500175void Manager::removeWatch(const fs::path& path)
176{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500177 // Delete Watch entry from map.
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500178 childWatchMap.erase(path);
179}
180
Jayanth Othayoth43096592017-07-20 02:17:37 -0500181void Manager::restore()
182{
183 fs::path dir(BMC_DUMP_PATH);
184 if (!fs::exists(dir) || fs::is_empty(dir))
185 {
186 return;
187 }
188
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500189 // Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
Jayanth Othayoth43096592017-07-20 02:17:37 -0500190 for (const auto& p : fs::directory_iterator(dir))
191 {
192 auto idStr = p.path().filename().string();
193
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500194 // Consider only directory's with dump id as name.
195 // Note: As per design one file per directory.
Jayanth Othayoth43096592017-07-20 02:17:37 -0500196 if ((fs::is_directory(p.path())) &&
197 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
198 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500199 lastEntryId =
200 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
Jayanth Othayoth43096592017-07-20 02:17:37 -0500201 auto fileIt = fs::directory_iterator(p.path());
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500202 // Create dump entry d-bus object.
Jayanth Othayoth43096592017-07-20 02:17:37 -0500203 if (fileIt != fs::end(fileIt))
204 {
205 createEntry(fileIt->path());
206 }
207 }
208 }
209}
210
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500211size_t Manager::getAllowedSize()
212{
213 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
214 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
215
216 auto size = 0;
217
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500218 // Get current size of the dump directory.
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500219 for (const auto& p : fs::recursive_directory_iterator(BMC_DUMP_PATH))
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500220 {
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500221 if (!fs::is_directory(p))
222 {
223 size += fs::file_size(p);
224 }
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500225 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500226
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500227 // Convert size into KB
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500228 size = size / 1024;
229
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500230 // Set the Dump size to Maximum if the free space is greater than
231 // Dump max size otherwise return the available size.
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500232
233 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
234
235 if (size < BMC_DUMP_MIN_SPACE_REQD)
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500236 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500237 // Reached to maximum limit
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500238 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
239 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500240 if (size > BMC_DUMP_MAX_SIZE)
241 {
242 size = BMC_DUMP_MAX_SIZE;
243 }
244
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500245 return size;
246}
247
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500248} // namespace dump
249} // namespace phosphor