blob: a42fce2082ae29c4dec75cd96bbaf1a787da59b0 [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
Dhruvaraj Subhashchandran4a98e8f2020-01-29 07:11:08 -06005#include "bmc_dump_entry.hpp"
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05006#include "dump_internal.hpp"
Dhruvaraj Subhashchandran33df5072020-01-30 01:48:02 -06007#include "system_dump_entry.hpp"
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05008#include "xyz/openbmc_project/Common/error.hpp"
Jayanth Othayothab7f9202017-08-02 06:24:58 -05009#include "xyz/openbmc_project/Dump/Create/error.hpp"
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050010
11#include <sys/inotify.h>
12#include <unistd.h>
13
14#include <phosphor-logging/elog-errors.hpp>
15#include <phosphor-logging/elog.hpp>
16#include <regex>
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050017
18namespace phosphor
19{
20namespace dump
21{
22
23using namespace sdbusplus::xyz::openbmc_project::Common::Error;
24using namespace phosphor::logging;
25
26namespace internal
27{
28
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050029void Manager::create(Type type, std::vector<std::string> fullPaths)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050030{
Jayanth Othayothd3273ea2017-07-12 22:55:32 -050031 dumpMgr.phosphor::dump::Manager::captureDump(type, fullPaths);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050032}
33
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050034} // namespace internal
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050035
36uint32_t Manager::createDump()
37{
38 std::vector<std::string> paths;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050039 return captureDump(Type::UserRequested, paths);
40}
41
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050042uint32_t Manager::captureDump(Type type,
43 const std::vector<std::string>& fullPaths)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050044{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050045 // Get Dump size.
Jayanth Othayoth9c155582017-08-09 07:47:45 -050046 auto size = getAllowedSize();
47
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050048 pid_t pid = fork();
49
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050050 if (pid == 0)
51 {
Jayanth Othayothf9009a22017-07-12 19:40:34 -050052 fs::path dumpPath(BMC_DUMP_PATH);
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050053 auto id = std::to_string(lastEntryId + 1);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050054 dumpPath /= id;
Jayanth Othayothf9009a22017-07-12 19:40:34 -050055
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050056 // get dreport type map entry
Marri Devender Rao0deb2872018-11-12 07:45:54 -060057 auto tempType = TypeMap.find(type);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050058
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050059 execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
60 id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
61 fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
62 tempType->second.c_str(), nullptr);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050063
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050064 // dreport script execution is failed.
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050065 auto error = errno;
Jayanth Othayoth9c155582017-08-09 07:47:45 -050066 log<level::ERR>("Error occurred during dreport function execution",
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050067 entry("ERRNO=%d", error));
68 elog<InternalFailure>();
69 }
70 else if (pid > 0)
71 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050072 auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
73 WEXITED | WSTOPPED, callback, nullptr);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050074 if (0 > rc)
75 {
76 // Failed to add to event loop
77 log<level::ERR>("Error occurred during the sd_event_add_child call",
Gunnar Mills11eaab72017-10-19 16:07:31 -050078 entry("RC=%d", rc));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050079 elog<InternalFailure>();
80 }
81 }
82 else
83 {
84 auto error = errno;
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050085 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050086 elog<InternalFailure>();
87 }
88
89 return ++lastEntryId;
90}
91
92void Manager::createEntry(const fs::path& file)
93{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050094 // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
95 static constexpr auto ID_POS = 1;
96 static constexpr auto EPOCHTIME_POS = 2;
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050097 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050098
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050099 std::smatch match;
100 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500101
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500102 if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500103 {
104 log<level::ERR>("Invalid Dump file name",
Joseph Reynoldsaf487622018-05-10 15:54:16 -0500105 entry("FILENAME=%s", file.filename().c_str()));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500106 return;
107 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500108
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500109 auto idString = match[ID_POS];
110 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500111
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500112 try
113 {
114 auto id = stoul(idString);
115 // Entry Object path.
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500116 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500117
Dhruvaraj Subhashchandran4a98e8f2020-01-29 07:11:08 -0600118 entries.insert(
119 std::make_pair(id, std::make_unique<bmc::Entry>(
120 bus, objPath.c_str(), id, stoull(msString),
121 fs::file_size(file), file, *this)));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500122 }
123 catch (const std::invalid_argument& e)
124 {
125 log<level::ERR>(e.what());
126 return;
127 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500128}
129
130void Manager::erase(uint32_t entryId)
131{
132 entries.erase(entryId);
133}
134
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500135void Manager::deleteAll()
136{
137 auto iter = entries.begin();
138 while (iter != entries.end())
139 {
140 auto& entry = iter->second;
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500141 ++iter;
Stanley Chud11d6132020-03-12 14:52:34 +0800142 entry->delete_();
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500143 }
144}
145
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500146void Manager::watchCallback(const UserMap& fileInfo)
147{
148 for (const auto& i : fileInfo)
149 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500150 // For any new dump file create dump entry object
151 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500152 if (IN_CLOSE_WRITE == i.second)
153 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500154 removeWatch(i.first);
155
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500156 createEntry(i.first);
157 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500158 // Start inotify watch on newly created directory.
159 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
160 {
161 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500162 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
163 std::bind(std::mem_fn(&phosphor::dump::Manager::watchCallback),
164 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500165
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500166 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500167 }
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500168 }
169}
170
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500171void Manager::removeWatch(const fs::path& path)
172{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500173 // Delete Watch entry from map.
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500174 childWatchMap.erase(path);
175}
176
Jayanth Othayoth43096592017-07-20 02:17:37 -0500177void Manager::restore()
178{
179 fs::path dir(BMC_DUMP_PATH);
180 if (!fs::exists(dir) || fs::is_empty(dir))
181 {
182 return;
183 }
184
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500185 // Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
Jayanth Othayoth43096592017-07-20 02:17:37 -0500186 for (const auto& p : fs::directory_iterator(dir))
187 {
188 auto idStr = p.path().filename().string();
189
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500190 // Consider only directory's with dump id as name.
191 // Note: As per design one file per directory.
Jayanth Othayoth43096592017-07-20 02:17:37 -0500192 if ((fs::is_directory(p.path())) &&
193 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
194 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500195 lastEntryId =
196 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
Jayanth Othayoth43096592017-07-20 02:17:37 -0500197 auto fileIt = fs::directory_iterator(p.path());
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500198 // Create dump entry d-bus object.
Jayanth Othayoth43096592017-07-20 02:17:37 -0500199 if (fileIt != fs::end(fileIt))
200 {
201 createEntry(fileIt->path());
202 }
203 }
204 }
205}
206
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500207size_t Manager::getAllowedSize()
208{
209 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
210 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
211
212 auto size = 0;
213
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500214 // Get current size of the dump directory.
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500215 for (const auto& p : fs::recursive_directory_iterator(BMC_DUMP_PATH))
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500216 {
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500217 if (!fs::is_directory(p))
218 {
219 size += fs::file_size(p);
220 }
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500221 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500222
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500223 // Convert size into KB
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500224 size = size / 1024;
225
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500226 // Set the Dump size to Maximum if the free space is greater than
227 // Dump max size otherwise return the available size.
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500228
229 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
230
231 if (size < BMC_DUMP_MIN_SPACE_REQD)
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500232 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500233 // Reached to maximum limit
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500234 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
235 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500236 if (size > BMC_DUMP_MAX_SIZE)
237 {
238 size = BMC_DUMP_MAX_SIZE;
239 }
240
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500241 return size;
242}
243
Dhruvaraj Subhashchandran33df5072020-01-30 01:48:02 -0600244void Manager::notify(NewDump::DumpType dumpType, uint32_t dumpId, uint64_t size)
245{
246 // Get the timestamp
247 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
248 std::chrono::system_clock::now().time_since_epoch())
249 .count();
250 // Get the id
251 auto id = lastEntryId + 1;
252 auto idString = std::to_string(id);
253 auto objPath = fs::path(OBJ_ENTRY) / idString;
254 entries.insert(std::make_pair(
255 id, std::make_unique<system::Entry>(bus, objPath.c_str(), id, ms, size,
256 dumpId, *this)));
257 lastEntryId++;
258}
259
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500260} // namespace dump
261} // namespace phosphor