blob: 27aefef69b0fa6eef5530b1cd41b036b0a9c7d6e [file] [log] [blame]
Jayanth Othayotha320c7c2017-06-14 07:17:21 -05001#pragma once
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -05002#include "dump_manager.hpp"
Dhruvaraj Subhashchandran36047102023-06-29 03:46:25 -05003#include "dump_types.hpp"
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -05004
Jayanth Othayothd02153c2017-07-02 22:29:42 -05005#include <systemd/sd-event.h>
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05006#include <unistd.h>
7
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -05008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/elog.hpp>
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050010#include <phosphor-logging/lg2.hpp>
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060011#include <sdbusplus/bus.hpp>
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050012#include <xyz/openbmc_project/Common/error.hpp>
Dhruvaraj Subhashchandrane4350f92023-06-29 05:57:47 -050013#include <xyz/openbmc_project/Dump/Create/common.hpp>
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050014#include <xyz/openbmc_project/Dump/Create/server.hpp>
Ramesh Iyyar22793862020-12-04 04:03:03 -060015#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050016#include <xyz/openbmc_project/State/Host/server.hpp>
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050017
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050018#include <memory>
19
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050020namespace phosphor
21{
22namespace dump
23{
24
Ramesh Iyyar22793862020-12-04 04:03:03 -060025using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
26 Progress::ProgressStages;
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050027using HostState =
28 sdbusplus::xyz::openbmc_project::State::server::Host::HostState;
Ramesh Iyyar22793862020-12-04 04:03:03 -060029
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050030using namespace phosphor::logging;
31using namespace sdbusplus::xyz::openbmc_project::Common::Error;
32
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050033/* Need a custom deleter for freeing up sd_event */
34struct EventDeleter
35{
36 void operator()(sd_event* event) const
37 {
38 event = sd_event_unref(event);
39 }
40};
41using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
42
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050043/** @struct CustomFd
44 *
45 * RAII wrapper for file descriptor.
46 */
47struct CustomFd
48{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050049 private:
50 /** @brief File descriptor */
51 int fd = -1;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050052
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050053 public:
54 CustomFd() = delete;
55 CustomFd(const CustomFd&) = delete;
56 CustomFd& operator=(const CustomFd&) = delete;
57 CustomFd(CustomFd&&) = delete;
58 CustomFd& operator=(CustomFd&&) = delete;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050059
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050060 /** @brief Saves File descriptor and uses it to do file operation
61 *
62 * @param[in] fd - File descriptor
63 */
Patrick Williams78e88402023-05-10 07:50:48 -050064 CustomFd(int fd) : fd(fd) {}
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050065
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050066 ~CustomFd()
67 {
68 if (fd >= 0)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050069 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050070 close(fd);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050071 }
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050072 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050073
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050074 int operator()() const
75 {
76 return fd;
77 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050078};
79
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060080/**
81 * @brief Get the bus service
82 *
83 * @param[in] bus - Bus to attach to.
84 * @param[in] path - D-Bus path name.
85 * @param[in] interface - D-Bus interface name.
86 * @return the bus service as a string
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050087 *
88 * @throws sdbusplus::exception::SdBusError - If any D-Bus error occurs during
89 * the call.
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060090 **/
Patrick Williams9b18bf22022-07-22 19:26:55 -050091std::string getService(sdbusplus::bus_t& bus, const std::string& path,
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060092 const std::string& interface);
93
Ramesh Iyyar22793862020-12-04 04:03:03 -060094/**
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050095 * @brief Read property value from the specified object and interface
96 * @param[in] bus D-Bus handle
97 * @param[in] service service which has implemented the interface
98 * @param[in] object object having has implemented the interface
99 * @param[in] intf interface having the property
100 * @param[in] prop name of the property to read
101 * @throws sdbusplus::exception::SdBusError if an error occurs in the dbus call
102 * @return property value
103 */
104template <typename T>
105T readDBusProperty(sdbusplus::bus_t& bus, const std::string& service,
106 const std::string& object, const std::string& intf,
107 const std::string& prop)
108{
109 T retVal{};
110 try
111 {
112 auto properties = bus.new_method_call(service.c_str(), object.c_str(),
113 "org.freedesktop.DBus.Properties",
114 "Get");
115 properties.append(intf);
116 properties.append(prop);
117 auto result = bus.call(properties);
118 result.read(retVal);
119 }
120 catch (const std::exception& ex)
121 {
122 lg2::error(
123 "Failed to get the property: {PROPERTY} interface: {INTERFACE} "
124 "object path: {OBJECT_PATH} error: {ERROR} ",
125 "PROPERTY", prop, "INTERFACE", intf, "OBJECT_PATH", object, "ERROR",
126 ex);
127 throw;
128 }
129 return retVal;
130}
131
132/**
133 * @brief Get the state value
134 *
135 * @param[in] intf - Interface to get the value
136 * @param[in] objPath - Object path of the service
137 * @param[in] state - State name to get
138 *
139 * @return The state value as type T on successful retrieval.
140 *
141 * @throws sdbusplus::exception for D-Bus failures and std::bad_variant_access
142 * for invalid value
143 */
144template <typename T>
145T getStateValue(const std::string& intf, const std::string& objPath,
146 const std::string& state)
147{
148 try
149 {
150 auto bus = sdbusplus::bus::new_default();
151 auto service = getService(bus, objPath, intf);
152 return std::get<T>(readDBusProperty<std::variant<T>>(
153 bus, service, objPath, intf, state));
154 }
155 catch (const sdbusplus::exception_t& e)
156 {
157 lg2::error(
158 "D-Bus call exception, OBJPATH: {OBJPATH}, "
159 "INTERFACE: {INTERFACE}, PROPERTY: {PROPERTY}, error: {ERROR}",
160 "OBJPATH", objPath, "INTERFACE", intf, "PROPERTY", state, "ERROR",
161 e);
162 throw;
163 }
164 catch (const std::bad_variant_access& e)
165 {
166 lg2::error("Exception raised while read state: {STATE} property "
167 "value, OBJPATH: {OBJPATH}, INTERFACE: {INTERFACE}, "
168 "error: {ERROR}",
169 "STATE", state, "OBJPATH", objPath, "INTERFACE", intf,
170 "ERROR", e);
171 throw;
172 }
173}
174
175/**
176 * @brief Get the host state
177 *
178 * @return HostState on success
179 *
180 * @throws std::runtime_error - If getting the state property fails
181 */
182inline HostState getHostState()
183{
184 constexpr auto hostStateInterface = "xyz.openbmc_project.State.Host";
185 // TODO Need to change host instance if multiple instead "0"
186 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0";
187 return getStateValue<HostState>(hostStateInterface, hostStateObjPath,
188 "CurrentHostState");
189}
190
191/**
Ramesh Iyyar22793862020-12-04 04:03:03 -0600192 * @brief Get the host boot progress stage
193 *
194 * @return BootProgress on success
Ramesh Iyyar22793862020-12-04 04:03:03 -0600195 *
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500196 * @throws std::runtime_error - If getting the state property fails
Ramesh Iyyar22793862020-12-04 04:03:03 -0600197 */
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500198inline BootProgress getBootProgress()
199{
200 constexpr auto bootProgressInterface =
201 "xyz.openbmc_project.State.Boot.Progress";
202 // TODO Need to change host instance if multiple instead "0"
203 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0";
204 return getStateValue<BootProgress>(bootProgressInterface, hostStateObjPath,
205 "BootProgress");
206}
Ramesh Iyyar22793862020-12-04 04:03:03 -0600207
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600208/**
209 * @brief Check whether host is running
210 *
211 * @return true if the host running else false.
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500212 *
213 * @throws std::runtime_error - If getting the boot progress failed
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600214 */
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500215inline bool isHostRunning()
216{
217 // TODO #ibm-openbmc/dev/2858 Revisit the method for finding whether host
218 // is running.
219 BootProgress bootProgressStatus = getBootProgress();
220 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
221 (bootProgressStatus == BootProgress::SystemSetup) ||
222 (bootProgressStatus == BootProgress::OSStart) ||
223 (bootProgressStatus == BootProgress::OSRunning) ||
224 (bootProgressStatus == BootProgress::PCIInit))
225 {
226 return true;
227 }
228 return false;
229}
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600230
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500231inline void extractOriginatorProperties(phosphor::dump::DumpCreateParams params,
232 std::string& originatorId,
233 originatorTypes& originatorType)
234{
235 using InvalidArgument =
236 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
237 using Argument = xyz::openbmc_project::Common::InvalidArgument;
238 using CreateParametersXYZ =
239 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters;
240
241 auto iter = params.find(
242 sdbusplus::xyz::openbmc_project::Dump::server::Create::
243 convertCreateParametersToString(CreateParametersXYZ::OriginatorId));
244 if (iter == params.end())
245 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500246 lg2::info("OriginatorId is not provided");
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500247 }
248 else
249 {
250 try
251 {
252 originatorId = std::get<std::string>(iter->second);
253 }
254 catch (const std::bad_variant_access& e)
255 {
256 // Exception will be raised if the input is not string
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500257 lg2::error("An invalid originatorId passed. It should be a string, "
258 "errormsg: {ERROR}",
259 "ERROR", e);
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500260 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_ID"),
261 Argument::ARGUMENT_VALUE("INVALID INPUT"));
262 }
263 }
264
265 iter = params.find(sdbusplus::xyz::openbmc_project::Dump::server::Create::
266 convertCreateParametersToString(
267 CreateParametersXYZ::OriginatorType));
268 if (iter == params.end())
269 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500270 lg2::info("OriginatorType is not provided. Replacing the string "
271 "with the default value");
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500272 originatorType = originatorTypes::Internal;
273 }
274 else
275 {
276 try
277 {
278 std::string type = std::get<std::string>(iter->second);
279 originatorType = sdbusplus::xyz::openbmc_project::Common::server::
280 OriginatedBy::convertOriginatorTypesFromString(type);
281 }
282 catch (const std::bad_variant_access& e)
283 {
284 // Exception will be raised if the input is not string
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500285 lg2::error("An invalid originatorType passed, errormsg: {ERROR}",
286 "ERROR", e);
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500287 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_TYPE"),
288 Argument::ARGUMENT_VALUE("INVALID INPUT"));
289 }
290 }
291}
292
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500293/**
294 * @brief Check whether host is quiesced
295 *
296 * @return true if the host is quiesced else false.
297 *
298 * @throws std::runtime_error - If getting the state failed
299 */
300inline bool isHostQuiesced()
301{
302 return (getHostState() == HostState::Quiesced);
303}
304
Dhruvaraj Subhashchandran36047102023-06-29 03:46:25 -0500305/** @brief Extract the dump create parameters
306 * @param[in] key - The name of the parameter
307 * @param[in] params - The map of parameters passed as input
308 *
309 * @return On success, a std::optional containing the value of the parameter
310 * (of type T). On failure (key not found in the map or the value is not of type
311 * T), returns an empty std::optional.
312 */
313template <typename T>
314T extractParameter(const std::string& key,
315 phosphor::dump::DumpCreateParams& params)
316{
317 using InvalidArgument =
318 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
319 using Argument = xyz::openbmc_project::Common::InvalidArgument;
320
321 auto it = params.find(key);
322 if (it != params.end())
323 {
324 const auto& [foundKey, variantValue] = *it;
325 if (std::holds_alternative<T>(variantValue))
326 {
327 return std::get<T>(variantValue);
328 }
329 else
330 {
331 lg2::error("An invalid input passed for key: {KEY}", "KEY", key);
332 elog<InvalidArgument>(Argument::ARGUMENT_NAME(key.c_str()),
333 Argument::ARGUMENT_VALUE("INVALID INPUT"));
334 }
335 }
336 return T{};
337}
338
Dhruvaraj Subhashchandranaa0937f2023-07-22 23:50:40 -0500339/**
340 * @brief This function fetches the dump type associated with a particular
341 * error.
342 *
343 * @param[in] params The map of parameters passed as input.
344 *
345 * @return The dump type associated with the error.
346 *
347 * @throw std::invalid_argument If the dump type associated with the error
348 * type is not found in the map.
349 */
350inline DumpTypes getErrorDumpType(phosphor::dump::DumpCreateParams& params)
351{
352 using CreateParameters =
353 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters;
354 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create;
355 using InvalidArgument =
356 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
357 using Argument = xyz::openbmc_project::Common::InvalidArgument;
358
359 std::string errorType = extractParameter<std::string>(
360 DumpIntr::convertCreateParametersToString(CreateParameters::ErrorType),
361 params);
362 if (!isErrorTypeValid(errorType))
363 {
364 lg2::error("An invalid error type passed type: {ERROR_TYPE}",
365 "ERROR_TYPE", errorType);
366 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ERROR_TYPE"),
367 Argument::ARGUMENT_VALUE(errorType.c_str()));
368 }
369 auto type = stringToDumpType(errorType);
370 if (type.has_value())
371 {
372 return type.value();
373 }
374
375 // Ideally this should never happen, because if the error type is valid
376 // it should be present in the dumpTypeToStringMap
377 throw std::invalid_argument{"Dump type not found"};
378}
379
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500380} // namespace dump
381} // namespace phosphor