blob: 74e40f09ae6c3c9dac47a1282c7804825bc02507 [file] [log] [blame]
Dhruvaraj Subhashchandran4a959842021-09-30 02:55:52 -05001#pragma once
2
3#include "dump-extensions/openpower-dumps/openpower_dumps_config.h"
4
5#include "dump_manager_bmcstored.hpp"
6#include "dump_utils.hpp"
7#include "host_dump_entry.hpp"
8#include "op_dump_util.hpp"
9#include "watch.hpp"
10#include "xyz/openbmc_project/Common/error.hpp"
11#include "xyz/openbmc_project/Dump/Create/error.hpp"
12#include "xyz/openbmc_project/Dump/NewDump/server.hpp"
13
14#include <fmt/core.h>
15#include <sys/inotify.h>
16#include <unistd.h>
17
18#include <com/ibm/Dump/Create/server.hpp>
19#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/elog.hpp>
21#include <sdeventplus/exception.hpp>
22#include <sdeventplus/source/base.hpp>
23#include <sdeventplus/source/child.hpp>
24#include <xyz/openbmc_project/Dump/Create/server.hpp>
25
26#include <ctime>
27#include <filesystem>
28#include <regex>
29
30namespace openpower
31{
32namespace dump
33{
34namespace hostdump
35{
36
37using namespace sdbusplus::xyz::openbmc_project::Common::Error;
38using namespace phosphor::logging;
39
40constexpr auto INVALID_DUMP_SIZE = 0;
41constexpr auto HOST_DUMP_COMMON_FILENAME_PART =
42 "_([0-9]+)_([0-9]+).([a-zA-Z0-9]+)";
43
44using CreateIface = sdbusplus::server::object::object<
45 sdbusplus::xyz::openbmc_project::Dump::server::Create,
46 sdbusplus::com::ibm::Dump::server::Create,
47 sdbusplus::xyz::openbmc_project::Dump::server::NewDump>;
48
49using UserMap = phosphor::dump::inotify::UserMap;
50
51using Watch = phosphor::dump::inotify::Watch;
52using ::sdeventplus::source::Child;
53
54using originatorTypes = sdbusplus::xyz::openbmc_project::Common::server::
55 OriginatedBy::OriginatorTypes;
56
57/** @class Manager
58 * @brief Host Dump manager implementation.
59 * @details A concrete implementation for the
60 * xyz.openbmc_project.Dump.Create
61 * com::ibm::Dump::Create and
62 * xyz::openbmc_project::Dump::NewDump D-Bus APIs
63 */
64template <typename T>
65class Manager :
66 virtual public CreateIface,
67 public phosphor::dump::bmc_stored::Manager
68{
69 public:
70 Manager() = delete;
71 Manager(const Manager&) = default;
72 Manager& operator=(const Manager&) = delete;
73 Manager(Manager&&) = delete;
74 Manager& operator=(Manager&&) = delete;
75 virtual ~Manager() = default;
76
77 /** @brief Constructor to put object onto bus at a dbus path.
78 * @param[in] bus - Bus to attach to.
79 * @param[in] event - Dump manager sd_event loop.
80 * @param[in] path - Path to attach at.
81 * @param[in] baseEntryPath - Base path for dump entry.
Dhruvaraj Subhashchandran34610be2021-12-12 22:40:07 -060082 * @param[in] startingId - Starting dump id
Dhruvaraj Subhashchandran4a959842021-09-30 02:55:52 -050083 * @param[in] filePath - Path where the dumps are stored.
84 * @param[in] dumpNamePrefix - Prefix to the dump filename
85 * @param[in] dumpTempFileDir - Temporary location of dump files
86 * @param[in] maxDumpSize - Maximum allowed size of dump file
87 * @param[in] minDumpSize - Minimum size of a usable dump
88 * @param[in] allocatedSize - Total allocated space for the dump.
89 */
90 Manager(sdbusplus::bus::bus& bus, const phosphor::dump::EventPtr& event,
91 const char* path, const std::string& baseEntryPath,
Dhruvaraj Subhashchandran34610be2021-12-12 22:40:07 -060092 uint32_t startingId, const char* filePath,
93 const std::string dumpNamePrefix, const std::string dumpTempFileDir,
94 const uint64_t maxDumpSize, const uint64_t minDumpSize,
95 const uint64_t allocatedSize) :
Dhruvaraj Subhashchandran4a959842021-09-30 02:55:52 -050096 CreateIface(bus, path),
97 phosphor::dump::bmc_stored::Manager(
Dhruvaraj Subhashchandran34610be2021-12-12 22:40:07 -060098 bus, event, path, baseEntryPath, startingId, filePath,
Dhruvaraj Subhashchandran4a959842021-09-30 02:55:52 -050099 dumpNamePrefix + HOST_DUMP_COMMON_FILENAME_PART, maxDumpSize,
100 minDumpSize, allocatedSize),
101 dumpNamePrefix(dumpNamePrefix), dumpTempFileDir(dumpTempFileDir)
102 {}
103
104 /** @brief Implementation for CreateDump
105 * Method to create a host dump entry when user requests for a
106 * new host dump
107 *
108 * @return object_path - The object path of the new dump entry.
109 */
110 sdbusplus::message::object_path
111 createDump(phosphor::dump::DumpCreateParams params) override
112 {
113 using InvalidArgument =
114 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
115 using Argument = xyz::openbmc_project::Common::InvalidArgument;
116 if (!params.empty())
117 {
118 log<level::ERR>(fmt::format("Dump type({}) accepts no additional "
119 "parameters, number of parameters({})",
120 dumpNamePrefix, params.size())
121 .c_str());
122 elog<InvalidArgument>(
123 Argument::ARGUMENT_NAME("NO_PARAMETERS_NEEDED"),
124 Argument::ARGUMENT_VALUE("INVALID_PARAMETERS"));
125 }
126
127 // Check dump policy
128 util::isOPDumpsEnabled();
129
130 auto size = getAllowedSize();
131
132 uint32_t id = ++lastEntryId;
133
134 // Entry Object path.
135 auto objPath =
136 std::filesystem::path(baseEntryPath) / std::to_string(id);
137
138 log<level::INFO>(fmt::format("Create dump type({}) with id({}) "
139 "available space: ({}) kilobytes",
140 dumpNamePrefix, id, size)
141 .c_str());
142
143 std::time_t timeStamp = std::time(nullptr);
144 createEntry(id, objPath, timeStamp, 0, std::string(),
145 phosphor::dump::OperationStatus::InProgress, std::string(),
146 originatorTypes::Internal);
147
148 return objPath.string();
149 }
150
151 /** @brief Notify the host dump manager about creation of a new dump.
152 * @param[in] dumpId - Id from the source of the dump.
153 * @param[in] size - Size of the dump.
154 */
155 void notify(uint32_t dumpId, uint64_t) override
156 {
157 try
158 {
159 captureDump(dumpId);
160 }
161 catch (std::exception& e)
162 {
163 log<level::ERR>(
164 fmt::format("Failed to package dump({}): id({}) errorMsg({})",
165 dumpNamePrefix, dumpId, e.what())
166 .c_str());
167 throw std::runtime_error("Failed to package dump");
168 }
169 }
170 /** @brief Create a Dump Entry Object
171 * @param[in] id - Id of the dump
172 * @param[in] objPath - Object path to attach to
173 * @param[in] ms - Dump creation timestamp since the epoch.
174 * @param[in] fileSize - Dump file size in bytes.
175 * @param[in] file - Name of dump file.
176 * @param[in] status - status of the dump.
177 * @param[in] originatorId - Id of the originator of the dump
178 * @param[in] originatorType - Originator type
179 */
180
181 virtual void createEntry(const uint32_t id, const std::string objPath,
182 const uint64_t ms, uint64_t fileSize,
183 const std::filesystem::path& file,
184 phosphor::dump::OperationStatus status,
185 std::string originatorId,
186 originatorTypes originatorType) override
187 {
188 try
189 {
190 entries.insert(std::make_pair(
191 id, std::make_unique<openpower::dump::hostdump::Entry<T>>(
192 bus, objPath.c_str(), id, ms, fileSize, file, status,
193 originatorId, originatorType, *this)));
194 }
195 catch (const std::invalid_argument& e)
196 {
197 log<level::ERR>(fmt::format("Error in creating host dump entry, "
198 "errormsg({}), OBJECTPATH({}), ID({})",
199 e.what(), objPath.c_str(), id)
200 .c_str());
201 throw std::runtime_error("Error in creating host dump entry");
202 }
203 }
204
205 private:
206 std::string dumpNamePrefix;
207 std::string dumpTempFileDir;
208
209 void captureDump(uint32_t dumpId)
210 {
211 std::string idStr;
212 try
213 {
214 idStr = std::to_string(dumpId);
215 }
216 catch (std::exception& e)
217 {
218 log<level::ERR>("Dump capture: Error converting idto string");
219 throw std::runtime_error(
220 "Dump capture: Error converting dump id to string");
221 }
222
223 // Get Dump size.
224 // TODO #ibm-openbmc/issues/3061
225 // Dump request will be rejected if there is not enough space for
226 // one complete dump, change this behavior to crate a partial dump
227 // with available space.
228 auto size = getAllowedSize();
229
230 auto dumpTempPath = std::filesystem::path(dumpTempFileDir) / idStr;
231
232 pid_t pid = fork();
233 if (pid == 0)
234 {
235 std::filesystem::path dumpPath(dumpDir);
236 dumpPath /= idStr;
237 execl("/usr/bin/opdreport", "opdreport", "-d", dumpPath.c_str(),
238 "-i", idStr.c_str(), "-s", std::to_string(size).c_str(), "-q",
239 "-v", "-p", dumpTempPath.c_str(), "-n",
240 dumpNamePrefix.c_str(), nullptr);
241
242 // opdreport script execution is failed.
243 auto error = errno;
244 log<level::ERR>(
245 fmt::format(
246 "Dump capture: Error occurred during "
247 "opdreport function execution, errno({}), dumpPrefix({}), "
248 "dumpPath({}), dumpSourcePath({}), allowedSize({})",
249 error, dumpNamePrefix.c_str(), dumpPath.c_str(),
250 dumpTempPath.c_str(), size)
251 .c_str());
252 throw std::runtime_error("Dump capture: Error occured during "
253 "opdreport script execution");
254 }
255 else if (pid > 0)
256 {
257 phosphor::dump::Entry* dumpEntry = NULL;
258 auto dumpIt = entries.find(dumpId);
259 if (dumpIt != entries.end())
260 {
261 dumpEntry = dumpIt->second.get();
262 }
263 Child::Callback callback = [this, dumpEntry,
264 pid](Child&, const siginfo_t* si) {
265 // Set progress as failed if packaging return error
266 if (si->si_status != 0)
267 {
268 log<level::ERR>("Dump packaging failed");
269 if (dumpEntry != nullptr)
270 {
271 reinterpret_cast<phosphor::dump::Entry*>(dumpEntry)
272 ->status(phosphor::dump::OperationStatus::Failed);
273 }
274 }
275 else
276 {
277 log<level::INFO>("Dump packaging completed");
278 }
279 this->childPtrMap.erase(pid);
280 };
281 try
282 {
283 childPtrMap.emplace(
284 pid, std::make_unique<Child>(eventLoop.get(), pid,
285 WEXITED | WSTOPPED,
286 std::move(callback)));
287 }
288 catch (const sdeventplus::SdEventError& ex)
289 {
290 // Failed to add to event loop
291 log<level::ERR>(
292 fmt::format("Dump capture: Error occurred during "
293 "the sdeventplus::source::Child ex({})",
294 ex.what())
295 .c_str());
296 throw std::runtime_error(
297 "Dump capture: Error occurred during the "
298 "sdeventplus::source::Child creation");
299 }
300 }
301 else
302 {
303 auto error = errno;
304 log<level::ERR>(
305 fmt::format(
306 "Dump capture: Error occurred during fork, errno({})",
307 error)
308 .c_str());
309 throw std::runtime_error(
310 "Dump capture: Error occurred during fork");
311 }
312 }
313};
314
315} // namespace hostdump
316} // namespace dump
317} // namespace openpower