blob: accd0da55c90fb9c63164fda69a4110f31ed7908 [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"
7#include "xyz/openbmc_project/Common/error.hpp"
Jayanth Othayothab7f9202017-08-02 06:24:58 -05008#include "xyz/openbmc_project/Dump/Create/error.hpp"
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05009
10#include <sys/inotify.h>
11#include <unistd.h>
12
13#include <phosphor-logging/elog-errors.hpp>
14#include <phosphor-logging/elog.hpp>
15#include <regex>
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050016
17namespace phosphor
18{
19namespace dump
20{
21
22using namespace sdbusplus::xyz::openbmc_project::Common::Error;
23using namespace phosphor::logging;
24
25namespace internal
26{
27
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050028void Manager::create(Type type, std::vector<std::string> fullPaths)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050029{
Jayanth Othayothd3273ea2017-07-12 22:55:32 -050030 dumpMgr.phosphor::dump::Manager::captureDump(type, fullPaths);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050031}
32
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050033} // namespace internal
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050034
35uint32_t Manager::createDump()
36{
37 std::vector<std::string> paths;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050038 return captureDump(Type::UserRequested, paths);
39}
40
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050041uint32_t Manager::captureDump(Type type,
42 const std::vector<std::string>& fullPaths)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050043{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050044 // Get Dump size.
Jayanth Othayoth9c155582017-08-09 07:47:45 -050045 auto size = getAllowedSize();
46
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050047 pid_t pid = fork();
48
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050049 if (pid == 0)
50 {
Jayanth Othayothf9009a22017-07-12 19:40:34 -050051 fs::path dumpPath(BMC_DUMP_PATH);
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050052 auto id = std::to_string(lastEntryId + 1);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050053 dumpPath /= id;
Jayanth Othayothf9009a22017-07-12 19:40:34 -050054
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050055 // get dreport type map entry
Marri Devender Rao0deb2872018-11-12 07:45:54 -060056 auto tempType = TypeMap.find(type);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050057
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050058 execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
59 id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
60 fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
61 tempType->second.c_str(), nullptr);
Jayanth Othayoth9c155582017-08-09 07:47:45 -050062
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050063 // dreport script execution is failed.
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050064 auto error = errno;
Jayanth Othayoth9c155582017-08-09 07:47:45 -050065 log<level::ERR>("Error occurred during dreport function execution",
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050066 entry("ERRNO=%d", error));
67 elog<InternalFailure>();
68 }
69 else if (pid > 0)
70 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050071 auto rc = sd_event_add_child(eventLoop.get(), nullptr, pid,
72 WEXITED | WSTOPPED, callback, nullptr);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050073 if (0 > rc)
74 {
75 // Failed to add to event loop
76 log<level::ERR>("Error occurred during the sd_event_add_child call",
Gunnar Mills11eaab72017-10-19 16:07:31 -050077 entry("RC=%d", rc));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050078 elog<InternalFailure>();
79 }
80 }
81 else
82 {
83 auto error = errno;
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050084 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050085 elog<InternalFailure>();
86 }
87
88 return ++lastEntryId;
89}
90
91void Manager::createEntry(const fs::path& file)
92{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050093 // Dump File Name format obmcdump_ID_EPOCHTIME.EXT
94 static constexpr auto ID_POS = 1;
95 static constexpr auto EPOCHTIME_POS = 2;
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050096 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050097
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050098 std::smatch match;
99 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500100
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500101 if (!((std::regex_search(name, match, file_regex)) && (match.size() > 0)))
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500102 {
103 log<level::ERR>("Invalid Dump file name",
Joseph Reynoldsaf487622018-05-10 15:54:16 -0500104 entry("FILENAME=%s", file.filename().c_str()));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500105 return;
106 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500107
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500108 auto idString = match[ID_POS];
109 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500110
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500111 try
112 {
113 auto id = stoul(idString);
114 // Entry Object path.
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500115 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500116
Dhruvaraj Subhashchandran4a98e8f2020-01-29 07:11:08 -0600117 entries.insert(
118 std::make_pair(id, std::make_unique<bmc::Entry>(
119 bus, objPath.c_str(), id, stoull(msString),
120 fs::file_size(file), file, *this)));
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500121 }
122 catch (const std::invalid_argument& e)
123 {
124 log<level::ERR>(e.what());
125 return;
126 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500127}
128
129void Manager::erase(uint32_t entryId)
130{
131 entries.erase(entryId);
132}
133
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500134void Manager::deleteAll()
135{
136 auto iter = entries.begin();
137 while (iter != entries.end())
138 {
139 auto& entry = iter->second;
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500140 ++iter;
Stanley Chud11d6132020-03-12 14:52:34 +0800141 entry->delete_();
Nagaraju Goruganti3c899a42017-09-12 06:14:46 -0500142 }
143}
144
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500145void Manager::watchCallback(const UserMap& fileInfo)
146{
147 for (const auto& i : fileInfo)
148 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500149 // For any new dump file create dump entry object
150 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500151 if (IN_CLOSE_WRITE == i.second)
152 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500153 removeWatch(i.first);
154
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500155 createEntry(i.first);
156 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500157 // Start inotify watch on newly created directory.
158 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
159 {
160 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500161 eventLoop, IN_NONBLOCK, IN_CLOSE_WRITE, EPOLLIN, i.first,
162 std::bind(std::mem_fn(&phosphor::dump::Manager::watchCallback),
163 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500164
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500165 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500166 }
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500167 }
168}
169
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500170void Manager::removeWatch(const fs::path& path)
171{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500172 // Delete Watch entry from map.
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500173 childWatchMap.erase(path);
174}
175
Jayanth Othayoth43096592017-07-20 02:17:37 -0500176void Manager::restore()
177{
178 fs::path dir(BMC_DUMP_PATH);
179 if (!fs::exists(dir) || fs::is_empty(dir))
180 {
181 return;
182 }
183
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500184 // Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
Jayanth Othayoth43096592017-07-20 02:17:37 -0500185 for (const auto& p : fs::directory_iterator(dir))
186 {
187 auto idStr = p.path().filename().string();
188
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500189 // Consider only directory's with dump id as name.
190 // Note: As per design one file per directory.
Jayanth Othayoth43096592017-07-20 02:17:37 -0500191 if ((fs::is_directory(p.path())) &&
192 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
193 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500194 lastEntryId =
195 std::max(lastEntryId, static_cast<uint32_t>(std::stoul(idStr)));
Jayanth Othayoth43096592017-07-20 02:17:37 -0500196 auto fileIt = fs::directory_iterator(p.path());
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500197 // Create dump entry d-bus object.
Jayanth Othayoth43096592017-07-20 02:17:37 -0500198 if (fileIt != fs::end(fileIt))
199 {
200 createEntry(fileIt->path());
201 }
202 }
203 }
204}
205
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500206size_t Manager::getAllowedSize()
207{
208 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
209 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
210
211 auto size = 0;
212
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500213 // Get current size of the dump directory.
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500214 for (const auto& p : fs::recursive_directory_iterator(BMC_DUMP_PATH))
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500215 {
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500216 if (!fs::is_directory(p))
217 {
218 size += fs::file_size(p);
219 }
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500220 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500221
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500222 // Convert size into KB
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500223 size = size / 1024;
224
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500225 // Set the Dump size to Maximum if the free space is greater than
226 // Dump max size otherwise return the available size.
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500227
228 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
229
230 if (size < BMC_DUMP_MIN_SPACE_REQD)
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500231 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500232 // Reached to maximum limit
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500233 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
234 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500235 if (size > BMC_DUMP_MAX_SIZE)
236 {
237 size = BMC_DUMP_MAX_SIZE;
238 }
239
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500240 return size;
241}
242
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500243} // namespace dump
244} // namespace phosphor