blob: ef840f3eb80e7b195cbf9ad300780bf609d48c35 [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
84 return ++lastEntryId;
85}
86
87void Manager::createEntry(const fs::path& file)
88{
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050089 //Dump File Name format obmcdump_ID_EPOCHTIME.EXT
90 static constexpr auto ID_POS = 1;
91 static constexpr auto EPOCHTIME_POS = 2;
92 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050093
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050094 std::smatch match;
95 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050096
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050097 if (!((std::regex_search(name, match, file_regex)) &&
98 (match.size() > 0)))
99 {
100 log<level::ERR>("Invalid Dump file name",
101 entry("Filename=%s", file.filename()));
102 return;
103 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500104
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500105 auto idString = match[ID_POS];
106 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500107
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500108 try
109 {
110 auto id = stoul(idString);
111 // Entry Object path.
112 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
113
114 entries.insert(std::make_pair(id,
115 std::make_unique<Entry>(
116 bus,
117 objPath.c_str(),
118 id,
119 stoull(msString),
120 fs::file_size(file),
121 file,
122 *this)));
123 }
124 catch (const std::invalid_argument& e)
125 {
126 log<level::ERR>(e.what());
127 return;
128 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500129}
130
131void Manager::erase(uint32_t entryId)
132{
133 entries.erase(entryId);
134}
135
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500136void Manager::watchCallback(const UserMap& fileInfo)
137{
138 for (const auto& i : fileInfo)
139 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500140 // For any new dump file create dump entry object
141 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500142 if (IN_CLOSE_WRITE == i.second)
143 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500144 removeWatch(i.first);
145
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500146 createEntry(i.first);
147 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500148 // Start inotify watch on newly created directory.
149 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
150 {
151 auto watchObj = std::make_unique<Watch>(
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500152 eventLoop,
153 IN_NONBLOCK,
154 IN_CLOSE_WRITE,
155 EPOLLIN,
156 i.first,
157 std::bind(
158 std::mem_fn(
159 &phosphor::dump::Manager::watchCallback),
160 this, std::placeholders::_1));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500161
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500162 childWatchMap.emplace(i.first, std::move(watchObj));
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500163 }
164
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500165 }
166}
167
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500168void Manager::removeWatch(const fs::path& path)
169{
170 //Delete Watch entry from map.
171 childWatchMap.erase(path);
172}
173
Jayanth Othayoth43096592017-07-20 02:17:37 -0500174void Manager::restore()
175{
176 fs::path dir(BMC_DUMP_PATH);
177 if (!fs::exists(dir) || fs::is_empty(dir))
178 {
179 return;
180 }
181
182 //Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
183 for (const auto& p : fs::directory_iterator(dir))
184 {
185 auto idStr = p.path().filename().string();
186
187 //Consider only directory's with dump id as name.
188 //Note: As per design one file per directory.
189 if ((fs::is_directory(p.path())) &&
190 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
191 {
192 lastEntryId = std::max(lastEntryId,
193 static_cast<uint32_t>(std::stoul(idStr)));
194 auto fileIt = fs::directory_iterator(p.path());
195 //Create dump entry d-bus object.
196 if (fileIt != fs::end(fileIt))
197 {
198 createEntry(fileIt->path());
199 }
200 }
201 }
202}
203
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500204size_t Manager::getAllowedSize()
205{
206 using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
207 using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
208
209 auto size = 0;
210
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500211 //Get current size of the dump directory.
212 for (const auto& p : fs::recursive_directory_iterator(BMC_DUMP_PATH))
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500213 {
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500214 if (!fs::is_directory(p))
215 {
216 size += fs::file_size(p);
217 }
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500218 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500219
220 //Convert size into KB
221 size = size / 1024;
222
223 //Set the Dump size to Maximum if the free space is greater than
224 //Dump max size otherwise return the available size.
225
226 size = (size > BMC_DUMP_TOTAL_SIZE ? 0 : BMC_DUMP_TOTAL_SIZE - size);
227
228 if (size < BMC_DUMP_MIN_SPACE_REQD)
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500229 {
230 //Reached to maximum limit
231 elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
232 }
Jayanth Othayoth104f57c2017-08-09 06:19:32 -0500233 if (size > BMC_DUMP_MAX_SIZE)
234 {
235 size = BMC_DUMP_MAX_SIZE;
236 }
237
Jayanth Othayothab7f9202017-08-02 06:24:58 -0500238 return size;
239}
240
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500241} //namespace dump
242} //namespace phosphor