blob: 953022eb8e4bf22541f3d0c10491e3eeef8d4ba2 [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 Subhashchandran6f2f0982023-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
Dhruvaraj Subhashchandran9527eea2023-06-29 05:57:47 -05008#include <errors_map.hpp>
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -05009#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/elog.hpp>
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050011#include <phosphor-logging/lg2.hpp>
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060012#include <sdbusplus/bus.hpp>
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050013#include <xyz/openbmc_project/Common/error.hpp>
Dhruvaraj Subhashchandran9527eea2023-06-29 05:57:47 -050014#include <xyz/openbmc_project/Dump/Create/common.hpp>
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050015#include <xyz/openbmc_project/Dump/Create/server.hpp>
Ramesh Iyyar22793862020-12-04 04:03:03 -060016#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050017#include <xyz/openbmc_project/State/Host/server.hpp>
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050018
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050019#include <memory>
20
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050021namespace phosphor
22{
23namespace dump
24{
25
Ramesh Iyyar22793862020-12-04 04:03:03 -060026using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
27 Progress::ProgressStages;
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050028using HostState =
29 sdbusplus::xyz::openbmc_project::State::server::Host::HostState;
Ramesh Iyyar22793862020-12-04 04:03:03 -060030
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -050031using namespace phosphor::logging;
32using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050034/* Need a custom deleter for freeing up sd_event */
35struct EventDeleter
36{
37 void operator()(sd_event* event) const
38 {
39 event = sd_event_unref(event);
40 }
41};
42using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
43
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050044/** @struct CustomFd
45 *
46 * RAII wrapper for file descriptor.
47 */
48struct CustomFd
49{
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050050 private:
51 /** @brief File descriptor */
52 int fd = -1;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050053
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050054 public:
55 CustomFd() = delete;
56 CustomFd(const CustomFd&) = delete;
57 CustomFd& operator=(const CustomFd&) = delete;
58 CustomFd(CustomFd&&) = delete;
59 CustomFd& operator=(CustomFd&&) = delete;
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050060
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050061 /** @brief Saves File descriptor and uses it to do file operation
62 *
63 * @param[in] fd - File descriptor
64 */
Patrick Williams78e88402023-05-10 07:50:48 -050065 CustomFd(int fd) : fd(fd) {}
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050066
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050067 ~CustomFd()
68 {
69 if (fd >= 0)
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050070 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050071 close(fd);
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050072 }
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050073 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050074
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050075 int operator()() const
76 {
77 return fd;
78 }
Jayanth Othayotha320c7c2017-06-14 07:17:21 -050079};
80
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060081/**
82 * @brief Get the bus service
83 *
84 * @param[in] bus - Bus to attach to.
85 * @param[in] path - D-Bus path name.
86 * @param[in] interface - D-Bus interface name.
87 * @return the bus service as a string
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050088 *
89 * @throws sdbusplus::exception::SdBusError - If any D-Bus error occurs during
90 * the call.
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060091 **/
Patrick Williams9b18bf22022-07-22 19:26:55 -050092std::string getService(sdbusplus::bus_t& bus, const std::string& path,
Jayanth Othayothd31be2c2020-02-04 02:56:45 -060093 const std::string& interface);
94
Ramesh Iyyar22793862020-12-04 04:03:03 -060095/**
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -050096 * @brief Read property value from the specified object and interface
97 * @param[in] bus D-Bus handle
98 * @param[in] service service which has implemented the interface
99 * @param[in] object object having has implemented the interface
100 * @param[in] intf interface having the property
101 * @param[in] prop name of the property to read
102 * @throws sdbusplus::exception::SdBusError if an error occurs in the dbus call
103 * @return property value
104 */
105template <typename T>
106T readDBusProperty(sdbusplus::bus_t& bus, const std::string& service,
107 const std::string& object, const std::string& intf,
108 const std::string& prop)
109{
110 T retVal{};
111 try
112 {
113 auto properties = bus.new_method_call(service.c_str(), object.c_str(),
114 "org.freedesktop.DBus.Properties",
115 "Get");
116 properties.append(intf);
117 properties.append(prop);
118 auto result = bus.call(properties);
119 result.read(retVal);
120 }
121 catch (const std::exception& ex)
122 {
123 lg2::error(
124 "Failed to get the property: {PROPERTY} interface: {INTERFACE} "
125 "object path: {OBJECT_PATH} error: {ERROR} ",
126 "PROPERTY", prop, "INTERFACE", intf, "OBJECT_PATH", object, "ERROR",
127 ex);
128 throw;
129 }
130 return retVal;
131}
132
133/**
134 * @brief Get the state value
135 *
136 * @param[in] intf - Interface to get the value
137 * @param[in] objPath - Object path of the service
138 * @param[in] state - State name to get
139 *
140 * @return The state value as type T on successful retrieval.
141 *
142 * @throws sdbusplus::exception for D-Bus failures and std::bad_variant_access
143 * for invalid value
144 */
145template <typename T>
146T getStateValue(const std::string& intf, const std::string& objPath,
147 const std::string& state)
148{
149 try
150 {
151 auto bus = sdbusplus::bus::new_default();
152 auto service = getService(bus, objPath, intf);
153 return std::get<T>(readDBusProperty<std::variant<T>>(
154 bus, service, objPath, intf, state));
155 }
156 catch (const sdbusplus::exception_t& e)
157 {
158 lg2::error(
159 "D-Bus call exception, OBJPATH: {OBJPATH}, "
160 "INTERFACE: {INTERFACE}, PROPERTY: {PROPERTY}, error: {ERROR}",
161 "OBJPATH", objPath, "INTERFACE", intf, "PROPERTY", state, "ERROR",
162 e);
163 throw;
164 }
165 catch (const std::bad_variant_access& e)
166 {
167 lg2::error("Exception raised while read state: {STATE} property "
168 "value, OBJPATH: {OBJPATH}, INTERFACE: {INTERFACE}, "
169 "error: {ERROR}",
170 "STATE", state, "OBJPATH", objPath, "INTERFACE", intf,
171 "ERROR", e);
172 throw;
173 }
174}
175
176/**
177 * @brief Get the host state
178 *
179 * @return HostState on success
180 *
181 * @throws std::runtime_error - If getting the state property fails
182 */
183inline HostState getHostState()
184{
185 constexpr auto hostStateInterface = "xyz.openbmc_project.State.Host";
186 // TODO Need to change host instance if multiple instead "0"
187 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0";
188 return getStateValue<HostState>(hostStateInterface, hostStateObjPath,
189 "CurrentHostState");
190}
191
192/**
Ramesh Iyyar22793862020-12-04 04:03:03 -0600193 * @brief Get the host boot progress stage
194 *
195 * @return BootProgress on success
Ramesh Iyyar22793862020-12-04 04:03:03 -0600196 *
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500197 * @throws std::runtime_error - If getting the state property fails
Ramesh Iyyar22793862020-12-04 04:03:03 -0600198 */
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500199inline BootProgress getBootProgress()
200{
201 constexpr auto bootProgressInterface =
202 "xyz.openbmc_project.State.Boot.Progress";
203 // TODO Need to change host instance if multiple instead "0"
204 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0";
205 return getStateValue<BootProgress>(bootProgressInterface, hostStateObjPath,
206 "BootProgress");
207}
Ramesh Iyyar22793862020-12-04 04:03:03 -0600208
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600209/**
210 * @brief Check whether host is running
211 *
212 * @return true if the host running else false.
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500213 *
214 * @throws std::runtime_error - If getting the boot progress failed
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600215 */
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500216inline bool isHostRunning()
217{
218 // TODO #ibm-openbmc/dev/2858 Revisit the method for finding whether host
219 // is running.
220 BootProgress bootProgressStatus = getBootProgress();
221 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
222 (bootProgressStatus == BootProgress::SystemSetup) ||
223 (bootProgressStatus == BootProgress::OSStart) ||
224 (bootProgressStatus == BootProgress::OSRunning) ||
225 (bootProgressStatus == BootProgress::PCIInit))
226 {
227 return true;
228 }
229 return false;
230}
Dhruvaraj Subhashchandran6a54d9a2020-12-17 22:24:37 -0600231
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500232inline void extractOriginatorProperties(phosphor::dump::DumpCreateParams params,
233 std::string& originatorId,
234 originatorTypes& originatorType)
235{
236 using InvalidArgument =
237 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
238 using Argument = xyz::openbmc_project::Common::InvalidArgument;
239 using CreateParametersXYZ =
240 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters;
241
242 auto iter = params.find(
243 sdbusplus::xyz::openbmc_project::Dump::server::Create::
244 convertCreateParametersToString(CreateParametersXYZ::OriginatorId));
245 if (iter == params.end())
246 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500247 lg2::info("OriginatorId is not provided");
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500248 }
249 else
250 {
251 try
252 {
253 originatorId = std::get<std::string>(iter->second);
254 }
255 catch (const std::bad_variant_access& e)
256 {
257 // Exception will be raised if the input is not string
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500258 lg2::error("An invalid originatorId passed. It should be a string, "
259 "errormsg: {ERROR}",
260 "ERROR", e);
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500261 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_ID"),
262 Argument::ARGUMENT_VALUE("INVALID INPUT"));
263 }
264 }
265
266 iter = params.find(sdbusplus::xyz::openbmc_project::Dump::server::Create::
267 convertCreateParametersToString(
268 CreateParametersXYZ::OriginatorType));
269 if (iter == params.end())
270 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500271 lg2::info("OriginatorType is not provided. Replacing the string "
272 "with the default value");
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500273 originatorType = originatorTypes::Internal;
274 }
275 else
276 {
277 try
278 {
279 std::string type = std::get<std::string>(iter->second);
280 originatorType = sdbusplus::xyz::openbmc_project::Common::server::
281 OriginatedBy::convertOriginatorTypesFromString(type);
282 }
283 catch (const std::bad_variant_access& e)
284 {
285 // Exception will be raised if the input is not string
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500286 lg2::error("An invalid originatorType passed, errormsg: {ERROR}",
287 "ERROR", e);
Asmitha Karunanithi74a1f392021-10-27 03:23:59 -0500288 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_TYPE"),
289 Argument::ARGUMENT_VALUE("INVALID INPUT"));
290 }
291 }
292}
293
Dhruvaraj Subhashchandran3a25e5b2022-03-22 08:06:20 -0500294/**
295 * @brief Check whether host is quiesced
296 *
297 * @return true if the host is quiesced else false.
298 *
299 * @throws std::runtime_error - If getting the state failed
300 */
301inline bool isHostQuiesced()
302{
303 return (getHostState() == HostState::Quiesced);
304}
305
Dhruvaraj Subhashchandran6f2f0982023-06-29 03:46:25 -0500306/**
307 * @brief Validates dump type and returns corresponding collection type
308 *
309 * This function checks the provided dump type against the specified category.
310 * If the dump type is empty, it defaults to "user". If the dump type does not
311 * exist or does not match with the specified category, it logs an error and
312 * throws an InvalidArgument exception.
313 *
314 * @param[in] type - The dump type to be validated.
315 * @param[in] category - The category to match against the dump type.
316 *
317 * @return The corresponding dump collection type if the dump type and category
318 * match an entry in the dumpTypeTable. If the type is empty or does not match
319 * any entry, it returns "user".
320 *
321 * @throws InvalidArgument - Thrown if the type does not match the specified
322 * category or does not exist in the table.
323 */
324DumpTypes validateDumpType(const std::string& type,
325 const std::string& category);
326
327/** @brief Extract the dump create parameters
328 * @param[in] key - The name of the parameter
329 * @param[in] params - The map of parameters passed as input
330 *
331 * @return On success, a std::optional containing the value of the parameter
332 * (of type T). On failure (key not found in the map or the value is not of type
333 * T), returns an empty std::optional.
334 */
335template <typename T>
336T extractParameter(const std::string& key,
337 phosphor::dump::DumpCreateParams& params)
338{
339 using InvalidArgument =
340 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
341 using Argument = xyz::openbmc_project::Common::InvalidArgument;
342
343 auto it = params.find(key);
344 if (it != params.end())
345 {
346 const auto& [foundKey, variantValue] = *it;
347 if (std::holds_alternative<T>(variantValue))
348 {
349 return std::get<T>(variantValue);
350 }
351 else
352 {
353 lg2::error("An invalid input passed for key: {KEY}", "KEY", key);
354 elog<InvalidArgument>(Argument::ARGUMENT_NAME(key.c_str()),
355 Argument::ARGUMENT_VALUE("INVALID INPUT"));
356 }
357 }
358 return T{};
359}
360
Dhruvaraj Subhashchandran9527eea2023-06-29 05:57:47 -0500361/**
362 * @brief This function fetches the dump type associated with a particular
363 * error.
364 *
365 * @param[in] params The map of parameters passed as input.
366 *
367 * @return The dump type associated with the error. If no additional error type
368 * is specified a generic elog type dump will be generated.
369 */
370inline DumpTypes getErrorDumpType(phosphor::dump::DumpCreateParams& params)
371{
372 using CreateParameters =
373 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters;
374 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create;
375 DumpTypes dumpType = DumpTypes::ELOG;
376 std::string errorType = extractParameter<std::string>(
377 DumpIntr::convertCreateParametersToString(CreateParameters::ErrorType),
378 params);
379 const auto elogIt = errorMap.find(errorType);
380 if (elogIt != errorMap.end())
381 {
382 auto type = stringToDumpType(errorType);
383 if (type.has_value())
384 {
385 dumpType = type.value();
386 }
387 }
388 return dumpType;
389}
390
Jayanth Othayotha320c7c2017-06-14 07:17:21 -0500391} // namespace dump
392} // namespace phosphor