blob: 7bf8a7b031934089c8baaac75cb15cb00c71e8a3 [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>
13#include <xyz/openbmc_project/Dump/Create/server.hpp>
Ramesh Iyyar22793862020-12-04 04:03:03 -060014#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050015#include <xyz/openbmc_project/State/Host/server.hpp>
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050016
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050017#include <memory>
18
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050019namespace phosphor
20{
21namespace dump
22{
23
Ramesh Iyyar22793862020-12-04 04:03:03 -060024using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
25 Progress::ProgressStages;
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050026using HostState =
27 sdbusplus::xyz::openbmc_project::State::server::Host::HostState;
Ramesh Iyyar22793862020-12-04 04:03:03 -060028
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050029using namespace phosphor::logging;
30using namespace sdbusplus::xyz::openbmc_project::Common::Error;
31
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050032/* Need a custom deleter for freeing up sd_event */
33struct EventDeleter
34{
35 void operator()(sd_event* event) const
36 {
37 event = sd_event_unref(event);
38 }
39};
40using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
41
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050042/** @struct CustomFd
43 *
44 * RAII wrapper for file descriptor.
45 */
46struct CustomFd
47{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050048 private:
49 /** @brief File descriptor */
50 int fd = -1;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050051
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050052 public:
53 CustomFd() = delete;
54 CustomFd(const CustomFd&) = delete;
55 CustomFd& operator=(const CustomFd&) = delete;
56 CustomFd(CustomFd&&) = delete;
57 CustomFd& operator=(CustomFd&&) = delete;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050058
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050059 /** @brief Saves File descriptor and uses it to do file operation
60 *
61 * @param[in] fd - File descriptor
62 */
Patrick Williams78e88402023-05-10 07:50:48 -050063 CustomFd(int fd) : fd(fd) {}
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050064
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050065 ~CustomFd()
66 {
67 if (fd >= 0)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050068 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050069 close(fd);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050070 }
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050071 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050072
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050073 int operator()() const
74 {
75 return fd;
76 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050077};
78
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060079/**
80 * @brief Get the bus service
81 *
82 * @param[in] bus - Bus to attach to.
83 * @param[in] path - D-Bus path name.
84 * @param[in] interface - D-Bus interface name.
85 * @return the bus service as a string
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050086 *
87 * @throws sdbusplus::exception::SdBusError - If any D-Bus error occurs during
88 * the call.
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060089 **/
Patrick Williams9b18bf22022-07-22 19:26:55 -050090std::string getService(sdbusplus::bus_t& bus, const std::string& path,
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060091 const std::string& interface);
92
Ramesh Iyyar22793862020-12-04 04:03:03 -060093/**
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050094 * @brief Read property value from the specified object and interface
95 * @param[in] bus D-Bus handle
96 * @param[in] service service which has implemented the interface
97 * @param[in] object object having has implemented the interface
98 * @param[in] intf interface having the property
99 * @param[in] prop name of the property to read
100 * @throws sdbusplus::exception::SdBusError if an error occurs in the dbus call
101 * @return property value
102 */
103template <typename T>
104T readDBusProperty(sdbusplus::bus_t& bus, const std::string& service,
105 const std::string& object, const std::string& intf,
106 const std::string& prop)
107{
108 T retVal{};
109 try
110 {
111 auto properties = bus.new_method_call(service.c_str(), object.c_str(),
112 "org.freedesktop.DBus.Properties",
113 "Get");
114 properties.append(intf);
115 properties.append(prop);
116 auto result = bus.call(properties);
117 result.read(retVal);
118 }
119 catch (const std::exception& ex)
120 {
121 lg2::error(
122 "Failed to get the property: {PROPERTY} interface: {INTERFACE} "
123 "object path: {OBJECT_PATH} error: {ERROR} ",
124 "PROPERTY", prop, "INTERFACE", intf, "OBJECT_PATH", object, "ERROR",
125 ex);
126 throw;
127 }
128 return retVal;
129}
130
131/**
132 * @brief Get the state value
133 *
134 * @param[in] intf - Interface to get the value
135 * @param[in] objPath - Object path of the service
136 * @param[in] state - State name to get
137 *
138 * @return The state value as type T on successful retrieval.
139 *
140 * @throws sdbusplus::exception for D-Bus failures and std::bad_variant_access
141 * for invalid value
142 */
143template <typename T>
144T getStateValue(const std::string& intf, const std::string& objPath,
145 const std::string& state)
146{
147 try
148 {
149 auto bus = sdbusplus::bus::new_default();
150 auto service = getService(bus, objPath, intf);
151 return std::get<T>(readDBusProperty<std::variant<T>>(
152 bus, service, objPath, intf, state));
153 }
154 catch (const sdbusplus::exception_t& e)
155 {
156 lg2::error(
157 "D-Bus call exception, OBJPATH: {OBJPATH}, "
158 "INTERFACE: {INTERFACE}, PROPERTY: {PROPERTY}, error: {ERROR}",
159 "OBJPATH", objPath, "INTERFACE", intf, "PROPERTY", state, "ERROR",
160 e);
161 throw;
162 }
163 catch (const std::bad_variant_access& e)
164 {
165 lg2::error("Exception raised while read state: {STATE} property "
166 "value, OBJPATH: {OBJPATH}, INTERFACE: {INTERFACE}, "
167 "error: {ERROR}",
168 "STATE", state, "OBJPATH", objPath, "INTERFACE", intf,
169 "ERROR", e);
170 throw;
171 }
172}
173
174/**
175 * @brief Get the host state
176 *
177 * @return HostState on success
178 *
179 * @throws std::runtime_error - If getting the state property fails
180 */
181inline HostState getHostState()
182{
183 constexpr auto hostStateInterface = "xyz.openbmc_project.State.Host";
184 // TODO Need to change host instance if multiple instead "0"
185 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0";
186 return getStateValue<HostState>(hostStateInterface, hostStateObjPath,
187 "CurrentHostState");
188}
189
190/**
Ramesh Iyyar22793862020-12-04 04:03:03 -0600191 * @brief Get the host boot progress stage
192 *
193 * @return BootProgress on success
Ramesh Iyyar22793862020-12-04 04:03:03 -0600194 *
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500195 * @throws std::runtime_error - If getting the state property fails
Ramesh Iyyar22793862020-12-04 04:03:03 -0600196 */
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500197inline BootProgress getBootProgress()
198{
199 constexpr auto bootProgressInterface =
200 "xyz.openbmc_project.State.Boot.Progress";
201 // TODO Need to change host instance if multiple instead "0"
202 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0";
203 return getStateValue<BootProgress>(bootProgressInterface, hostStateObjPath,
204 "BootProgress");
205}
Ramesh Iyyar22793862020-12-04 04:03:03 -0600206
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600207/**
208 * @brief Check whether host is running
209 *
210 * @return true if the host running else false.
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500211 *
212 * @throws std::runtime_error - If getting the boot progress failed
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600213 */
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500214inline bool isHostRunning()
215{
216 // TODO #ibm-openbmc/dev/2858 Revisit the method for finding whether host
217 // is running.
218 BootProgress bootProgressStatus = getBootProgress();
219 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
220 (bootProgressStatus == BootProgress::SystemSetup) ||
221 (bootProgressStatus == BootProgress::OSStart) ||
222 (bootProgressStatus == BootProgress::OSRunning) ||
223 (bootProgressStatus == BootProgress::PCIInit))
224 {
225 return true;
226 }
227 return false;
228}
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600229
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500230inline void extractOriginatorProperties(phosphor::dump::DumpCreateParams params,
231 std::string& originatorId,
232 originatorTypes& originatorType)
233{
234 using InvalidArgument =
235 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
236 using Argument = xyz::openbmc_project::Common::InvalidArgument;
237 using CreateParametersXYZ =
238 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters;
239
240 auto iter = params.find(
241 sdbusplus::xyz::openbmc_project::Dump::server::Create::
242 convertCreateParametersToString(CreateParametersXYZ::OriginatorId));
243 if (iter == params.end())
244 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500245 lg2::info("OriginatorId is not provided");
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500246 }
247 else
248 {
249 try
250 {
251 originatorId = std::get<std::string>(iter->second);
252 }
253 catch (const std::bad_variant_access& e)
254 {
255 // Exception will be raised if the input is not string
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500256 lg2::error("An invalid originatorId passed. It should be a string, "
257 "errormsg: {ERROR}",
258 "ERROR", e);
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500259 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_ID"),
260 Argument::ARGUMENT_VALUE("INVALID INPUT"));
261 }
262 }
263
264 iter = params.find(sdbusplus::xyz::openbmc_project::Dump::server::Create::
265 convertCreateParametersToString(
266 CreateParametersXYZ::OriginatorType));
267 if (iter == params.end())
268 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500269 lg2::info("OriginatorType is not provided. Replacing the string "
270 "with the default value");
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500271 originatorType = originatorTypes::Internal;
272 }
273 else
274 {
275 try
276 {
277 std::string type = std::get<std::string>(iter->second);
278 originatorType = sdbusplus::xyz::openbmc_project::Common::server::
279 OriginatedBy::convertOriginatorTypesFromString(type);
280 }
281 catch (const std::bad_variant_access& e)
282 {
283 // Exception will be raised if the input is not string
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500284 lg2::error("An invalid originatorType passed, errormsg: {ERROR}",
285 "ERROR", e);
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500286 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_TYPE"),
287 Argument::ARGUMENT_VALUE("INVALID INPUT"));
288 }
289 }
290}
291
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500292/**
293 * @brief Check whether host is quiesced
294 *
295 * @return true if the host is quiesced else false.
296 *
297 * @throws std::runtime_error - If getting the state failed
298 */
299inline bool isHostQuiesced()
300{
301 return (getHostState() == HostState::Quiesced);
302}
303
Dhruvaraj Subhashchandran36047102023-06-29 03:46:25 -0500304/** @brief Extract the dump create parameters
305 * @param[in] key - The name of the parameter
306 * @param[in] params - The map of parameters passed as input
307 *
308 * @return On success, a std::optional containing the value of the parameter
309 * (of type T). On failure (key not found in the map or the value is not of type
310 * T), returns an empty std::optional.
311 */
312template <typename T>
313T extractParameter(const std::string& key,
314 phosphor::dump::DumpCreateParams& params)
315{
316 using InvalidArgument =
317 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
318 using Argument = xyz::openbmc_project::Common::InvalidArgument;
319
320 auto it = params.find(key);
321 if (it != params.end())
322 {
323 const auto& [foundKey, variantValue] = *it;
324 if (std::holds_alternative<T>(variantValue))
325 {
326 return std::get<T>(variantValue);
327 }
328 else
329 {
330 lg2::error("An invalid input passed for key: {KEY}", "KEY", key);
331 elog<InvalidArgument>(Argument::ARGUMENT_NAME(key.c_str()),
332 Argument::ARGUMENT_VALUE("INVALID INPUT"));
333 }
334 }
335 return T{};
336}
337
Dhruvaraj Subhashchandranaa0937f2023-07-22 23:50:40 -0500338/**
339 * @brief This function fetches the dump type associated with a particular
340 * error.
341 *
342 * @param[in] params The map of parameters passed as input.
343 *
344 * @return The dump type associated with the error.
345 *
346 * @throw std::invalid_argument If the dump type associated with the error
347 * type is not found in the map.
348 */
349inline DumpTypes getErrorDumpType(phosphor::dump::DumpCreateParams& params)
350{
351 using CreateParameters =
352 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters;
353 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create;
354 using InvalidArgument =
355 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
356 using Argument = xyz::openbmc_project::Common::InvalidArgument;
357
358 std::string errorType = extractParameter<std::string>(
359 DumpIntr::convertCreateParametersToString(CreateParameters::ErrorType),
360 params);
361 if (!isErrorTypeValid(errorType))
362 {
363 lg2::error("An invalid error type passed type: {ERROR_TYPE}",
364 "ERROR_TYPE", errorType);
365 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ERROR_TYPE"),
366 Argument::ARGUMENT_VALUE(errorType.c_str()));
367 }
368 auto type = stringToDumpType(errorType);
369 if (type.has_value())
370 {
371 return type.value();
372 }
373
374 // Ideally this should never happen, because if the error type is valid
375 // it should be present in the dumpTypeToStringMap
376 throw std::invalid_argument{"Dump type not found"};
377}
378
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500379} // namespace dump
380} // namespace phosphor