blob: 80e117b1c5288ff116b46615441eb13d0b4c0beb [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;
37
38 return captureDump(Type::UserRequested, paths);
39}
40
41uint32_t Manager::captureDump(
42 Type type,
43 const std::vector<std::string>& fullPaths)
44{
45 pid_t pid = fork();
46
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050047 if (pid == 0)
48 {
Jayanth Othayothf9009a22017-07-12 19:40:34 -050049 fs::path dumpPath(BMC_DUMP_PATH);
50
51 dumpPath /= std::to_string(lastEntryId + 1);
Jayanth Othayothf655cb42017-07-24 02:05:38 -050052 execl("/usr/bin/ffdc", "ffdc", "-d", dumpPath.c_str(), "-e", nullptr);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050053
54 //ffdc script execution is failed.
55 auto error = errno;
56 log<level::ERR>("Error occurred during ffdc function execution",
57 entry("ERRNO=%d", error));
58 elog<InternalFailure>();
59 }
60 else if (pid > 0)
61 {
62 auto rc = sd_event_add_child(eventLoop.get(),
63 nullptr,
64 pid,
65 WEXITED | WSTOPPED,
66 callback,
67 nullptr);
68 if (0 > rc)
69 {
70 // Failed to add to event loop
71 log<level::ERR>("Error occurred during the sd_event_add_child call",
72 entry("rc=%d", rc));
73 elog<InternalFailure>();
74 }
75 }
76 else
77 {
78 auto error = errno;
79 log<level::ERR>("Error occurred during fork",
80 entry("ERRNO=%d", error));
81 elog<InternalFailure>();
82 }
83
Jayanth Othayothab7f9202017-08-02 06:24:58 -050084 //Increment active dump count.
85 activeDumpCount++;
86
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050087 return ++lastEntryId;
88}
89
90void Manager::createEntry(const fs::path& file)
91{
Jayanth Othayothab7f9202017-08-02 06:24:58 -050092 //Decrement the Dump in progress counter.
93 activeDumpCount = (activeDumpCount == 0 ? 0 : activeDumpCount - 1);
94
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050095 //Dump File Name format obmcdump_ID_EPOCHTIME.EXT
96 static constexpr auto ID_POS = 1;
97 static constexpr auto EPOCHTIME_POS = 2;
98 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050099
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500100 std::smatch match;
101 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500102
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500103 if (!((std::regex_search(name, match, file_regex)) &&
104 (match.size() > 0)))
105 {
106 log<level::ERR>("Invalid Dump file name",
107 entry("Filename=%s", file.filename()));
108 return;
109 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500110
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500111 auto idString = match[ID_POS];
112 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500113
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500114 try
115 {
116 auto id = stoul(idString);
117 // Entry Object path.
118 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
119
120 entries.insert(std::make_pair(id,
121 std::make_unique<Entry>(
122 bus,
123 objPath.c_str(),
124 id,
125 stoull(msString),
126 fs::file_size(file),
127 file,
128 *this)));
129 }
130 catch (const std::invalid_argument& e)
131 {
132 log<level::ERR>(e.what());
133 return;
134 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500135}
136
137void Manager::erase(uint32_t entryId)
138{
139 entries.erase(entryId);
140}
141
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500142void Manager::watchCallback(const UserMap& fileInfo)
143{
144 for (const auto& i : fileInfo)
145 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500146 // For any new dump file create dump entry object
147 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500148 if (IN_CLOSE_WRITE == i.second)
149 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500150 removeWatch(i.first);
151
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500152 createEntry(i.first);
153 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500154 // Start inotify watch on newly created directory.
155 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
156 {
157 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500158 eventLoop,
159 IN_NONBLOCK,
160 IN_CLOSE_WRITE,
161 EPOLLIN,
162 i.first,
163 std::bind(
164 std::mem_fn(
165 &phosphor::dump::Manager::watchCallback),
166 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500167
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500168 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500169 }
170
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500171 }
172}
173
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500174void Manager::removeWatch(const fs::path& path)
175{
176 //Delete Watch entry from map.
177 childWatchMap.erase(path);
178}
179
Jayanth Othayoth43096592017-07-20 02:17:37 -0500180void Manager::restore()
181{
182 fs::path dir(BMC_DUMP_PATH);
183 if (!fs::exists(dir) || fs::is_empty(dir))
184 {
185 return;
186 }
187
188 //Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
189 for (const auto& p : fs::directory_iterator(dir))
190 {
191 auto idStr = p.path().filename().string();
192
193 //Consider only directory's with dump id as name.
194 //Note: As per design one file per directory.
195 if ((fs::is_directory(p.path())) &&
196 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
197 {
198 lastEntryId = std::max(lastEntryId,
199 static_cast<uint32_t>(std::stoul(idStr)));
200 auto fileIt = fs::directory_iterator(p.path());
201 //Create dump entry d-bus object.
202 if (fileIt != fs::end(fileIt))
203 {
204 createEntry(fileIt->path());
205 }
206 }
207 }
208}
209
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500210size_t Manager::getAllowedSize()
211{
212 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
213 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
214
215 auto size = 0;
216
217 // Maximum number of dump is based on total dump size
218 // and individual dump Max size configured in the system.
219 // Set the new dump size to max, in case sum of available
220 // dump and active dumps is less than maximum number of dumps.
221
222 constexpr auto dumpCount = BMC_DUMP_TOTAL_SIZE / BMC_DUMP_MAX_SIZE;
223
224 if ((entries.size() + activeDumpCount) < dumpCount)
225 {
226 size = BMC_DUMP_MAX_SIZE;
227 }
228 else
229 {
230 //Reached to maximum limit
231 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
232 }
233 return size;
234}
235
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500236} //namespace dump
237} //namespace phosphor