blob: 3775842d00bc2f625ad5343b03bda2f380b15ad4 [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
5#include <phosphor-logging/elog-errors.hpp>
6
7#include "dump_manager.hpp"
8#include "dump_internal.hpp"
9#include "xyz/openbmc_project/Common/error.hpp"
10#include "config.h"
11
12namespace phosphor
13{
14namespace dump
15{
16
17using namespace sdbusplus::xyz::openbmc_project::Common::Error;
18using namespace phosphor::logging;
19
20namespace internal
21{
22
23void Manager::create(
24 Type type,
25 std::vector<std::string> fullPaths)
26{
Jayanth Othayothd3273ea2017-07-12 22:55:32 -050027 dumpMgr.phosphor::dump::Manager::captureDump(type, fullPaths);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050028}
29
30} //namepsace internal
31
32uint32_t Manager::createDump()
33{
34 std::vector<std::string> paths;
35
36 return captureDump(Type::UserRequested, paths);
37}
38
39uint32_t Manager::captureDump(
40 Type type,
41 const std::vector<std::string>& fullPaths)
42{
43 pid_t pid = fork();
44
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050045 if (pid == 0)
46 {
Jayanth Othayothf9009a22017-07-12 19:40:34 -050047 fs::path dumpPath(BMC_DUMP_PATH);
48
49 dumpPath /= std::to_string(lastEntryId + 1);
50 execl("/usr/bin/ffdc", "ffdc", "-d", dumpPath.c_str(), nullptr);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050051
52 //ffdc script execution is failed.
53 auto error = errno;
54 log<level::ERR>("Error occurred during ffdc function execution",
55 entry("ERRNO=%d", error));
56 elog<InternalFailure>();
57 }
58 else if (pid > 0)
59 {
60 auto rc = sd_event_add_child(eventLoop.get(),
61 nullptr,
62 pid,
63 WEXITED | WSTOPPED,
64 callback,
65 nullptr);
66 if (0 > rc)
67 {
68 // Failed to add to event loop
69 log<level::ERR>("Error occurred during the sd_event_add_child call",
70 entry("rc=%d", rc));
71 elog<InternalFailure>();
72 }
73 }
74 else
75 {
76 auto error = errno;
77 log<level::ERR>("Error occurred during fork",
78 entry("ERRNO=%d", error));
79 elog<InternalFailure>();
80 }
81
82 return ++lastEntryId;
83}
84
85void Manager::createEntry(const fs::path& file)
86{
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050087 //Dump File Name format obmcdump_ID_EPOCHTIME.EXT
88 static constexpr auto ID_POS = 1;
89 static constexpr auto EPOCHTIME_POS = 2;
90 std::regex file_regex("obmcdump_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)");
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050091
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050092 std::smatch match;
93 std::string name = file.filename();
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050094
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -050095 if (!((std::regex_search(name, match, file_regex)) &&
96 (match.size() > 0)))
97 {
98 log<level::ERR>("Invalid Dump file name",
99 entry("Filename=%s", file.filename()));
100 return;
101 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500102
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500103 auto idString = match[ID_POS];
104 auto msString = match[EPOCHTIME_POS];
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500105
Jayanth Othayoth481bb3d2017-07-13 03:33:34 -0500106 try
107 {
108 auto id = stoul(idString);
109 // Entry Object path.
110 auto objPath = fs::path(OBJ_ENTRY) / std::to_string(id);
111
112 entries.insert(std::make_pair(id,
113 std::make_unique<Entry>(
114 bus,
115 objPath.c_str(),
116 id,
117 stoull(msString),
118 fs::file_size(file),
119 file,
120 *this)));
121 }
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
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500134void Manager::watchCallback(const UserMap& fileInfo)
135{
136 for (const auto& i : fileInfo)
137 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500138 // For any new dump file create dump entry object
139 // and associated inotify watch.
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500140 if (IN_CLOSE_WRITE == i.second)
141 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500142 removeWatch(i.first);
143
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500144 createEntry(i.first);
145 }
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500146 // Start inotify watch on newly created directory.
147 else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
148 {
149 auto watchObj = std::make_unique<Watch>(
150 eventLoop,
151 IN_NONBLOCK,
152 IN_CLOSE_WRITE,
153 EPOLLIN,
154 i.first,
155 std::bind(
156 std::mem_fn(
157 &phosphor::dump::Manager::watchCallback),
158 this, std::placeholders::_1));
159
160 childWatchMap.emplace(i.first, std::move(watchObj));
161 }
162
Jayanth Othayothbcb174b2017-07-02 06:29:24 -0500163 }
164}
165
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500166void Manager::removeWatch(const fs::path& path)
167{
168 //Delete Watch entry from map.
169 childWatchMap.erase(path);
170}
171
Jayanth Othayoth43096592017-07-20 02:17:37 -0500172void Manager::restore()
173{
174 fs::path dir(BMC_DUMP_PATH);
175 if (!fs::exists(dir) || fs::is_empty(dir))
176 {
177 return;
178 }
179
180 //Dump file path: <BMC_DUMP_PATH>/<id>/<filename>
181 for (const auto& p : fs::directory_iterator(dir))
182 {
183 auto idStr = p.path().filename().string();
184
185 //Consider only directory's with dump id as name.
186 //Note: As per design one file per directory.
187 if ((fs::is_directory(p.path())) &&
188 std::all_of(idStr.begin(), idStr.end(), ::isdigit))
189 {
190 lastEntryId = std::max(lastEntryId,
191 static_cast<uint32_t>(std::stoul(idStr)));
192 auto fileIt = fs::directory_iterator(p.path());
193 //Create dump entry d-bus object.
194 if (fileIt != fs::end(fileIt))
195 {
196 createEntry(fileIt->path());
197 }
198 }
199 }
200}
201
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500202} //namespace dump
203} //namespace phosphor