1 #pragma once 2 #include "dump_manager.hpp" 3 4 #include <systemd/sd-event.h> 5 #include <unistd.h> 6 7 #include <phosphor-logging/elog-errors.hpp> 8 #include <phosphor-logging/elog.hpp> 9 #include <phosphor-logging/lg2.hpp> 10 #include <sdbusplus/bus.hpp> 11 #include <xyz/openbmc_project/Common/error.hpp> 12 #include <xyz/openbmc_project/Dump/Create/server.hpp> 13 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp> 14 #include <xyz/openbmc_project/State/Host/server.hpp> 15 16 #include <memory> 17 18 namespace phosphor 19 { 20 namespace dump 21 { 22 23 using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server:: 24 Progress::ProgressStages; 25 using HostState = 26 sdbusplus::xyz::openbmc_project::State::server::Host::HostState; 27 28 using namespace phosphor::logging; 29 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 30 31 /* Need a custom deleter for freeing up sd_event */ 32 struct EventDeleter 33 { 34 void operator()(sd_event* event) const 35 { 36 event = sd_event_unref(event); 37 } 38 }; 39 using EventPtr = std::unique_ptr<sd_event, EventDeleter>; 40 41 /** @struct CustomFd 42 * 43 * RAII wrapper for file descriptor. 44 */ 45 struct CustomFd 46 { 47 private: 48 /** @brief File descriptor */ 49 int fd = -1; 50 51 public: 52 CustomFd() = delete; 53 CustomFd(const CustomFd&) = delete; 54 CustomFd& operator=(const CustomFd&) = delete; 55 CustomFd(CustomFd&&) = delete; 56 CustomFd& operator=(CustomFd&&) = delete; 57 58 /** @brief Saves File descriptor and uses it to do file operation 59 * 60 * @param[in] fd - File descriptor 61 */ 62 CustomFd(int fd) : fd(fd) {} 63 64 ~CustomFd() 65 { 66 if (fd >= 0) 67 { 68 close(fd); 69 } 70 } 71 72 int operator()() const 73 { 74 return fd; 75 } 76 }; 77 78 /** 79 * @brief Get the bus service 80 * 81 * @param[in] bus - Bus to attach to. 82 * @param[in] path - D-Bus path name. 83 * @param[in] interface - D-Bus interface name. 84 * @return the bus service as a string 85 * 86 * @throws sdbusplus::exception::SdBusError - If any D-Bus error occurs during 87 * the call. 88 **/ 89 std::string getService(sdbusplus::bus_t& bus, const std::string& path, 90 const std::string& interface); 91 92 /** 93 * @brief Read property value from the specified object and interface 94 * @param[in] bus D-Bus handle 95 * @param[in] service service which has implemented the interface 96 * @param[in] object object having has implemented the interface 97 * @param[in] intf interface having the property 98 * @param[in] prop name of the property to read 99 * @throws sdbusplus::exception::SdBusError if an error occurs in the dbus call 100 * @return property value 101 */ 102 template <typename T> 103 T readDBusProperty(sdbusplus::bus_t& bus, const std::string& service, 104 const std::string& object, const std::string& intf, 105 const std::string& prop) 106 { 107 T retVal{}; 108 try 109 { 110 auto properties = bus.new_method_call(service.c_str(), object.c_str(), 111 "org.freedesktop.DBus.Properties", 112 "Get"); 113 properties.append(intf); 114 properties.append(prop); 115 auto result = bus.call(properties); 116 result.read(retVal); 117 } 118 catch (const std::exception& ex) 119 { 120 lg2::error( 121 "Failed to get the property: {PROPERTY} interface: {INTERFACE} " 122 "object path: {OBJECT_PATH} error: {ERROR} ", 123 "PROPERTY", prop, "INTERFACE", intf, "OBJECT_PATH", object, "ERROR", 124 ex); 125 throw; 126 } 127 return retVal; 128 } 129 130 /** 131 * @brief Get the state value 132 * 133 * @param[in] intf - Interface to get the value 134 * @param[in] objPath - Object path of the service 135 * @param[in] state - State name to get 136 * 137 * @return The state value as type T on successful retrieval. 138 * 139 * @throws sdbusplus::exception for D-Bus failures and std::bad_variant_access 140 * for invalid value 141 */ 142 template <typename T> 143 T getStateValue(const std::string& intf, const std::string& objPath, 144 const std::string& state) 145 { 146 try 147 { 148 auto bus = sdbusplus::bus::new_default(); 149 auto service = getService(bus, objPath, intf); 150 return std::get<T>(readDBusProperty<std::variant<T>>( 151 bus, service, objPath, intf, state)); 152 } 153 catch (const sdbusplus::exception_t& e) 154 { 155 lg2::error( 156 "D-Bus call exception, OBJPATH: {OBJPATH}, " 157 "INTERFACE: {INTERFACE}, PROPERTY: {PROPERTY}, error: {ERROR}", 158 "OBJPATH", objPath, "INTERFACE", intf, "PROPERTY", state, "ERROR", 159 e); 160 throw; 161 } 162 catch (const std::bad_variant_access& e) 163 { 164 lg2::error("Exception raised while read state: {STATE} property " 165 "value, OBJPATH: {OBJPATH}, INTERFACE: {INTERFACE}, " 166 "error: {ERROR}", 167 "STATE", state, "OBJPATH", objPath, "INTERFACE", intf, 168 "ERROR", e); 169 throw; 170 } 171 } 172 173 /** 174 * @brief Get the host state 175 * 176 * @return HostState on success 177 * 178 * @throws std::runtime_error - If getting the state property fails 179 */ 180 inline HostState getHostState() 181 { 182 constexpr auto hostStateInterface = "xyz.openbmc_project.State.Host"; 183 // TODO Need to change host instance if multiple instead "0" 184 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0"; 185 return getStateValue<HostState>(hostStateInterface, hostStateObjPath, 186 "CurrentHostState"); 187 } 188 189 /** 190 * @brief Get the host boot progress stage 191 * 192 * @return BootProgress on success 193 * 194 * @throws std::runtime_error - If getting the state property fails 195 */ 196 inline BootProgress getBootProgress() 197 { 198 constexpr auto bootProgressInterface = 199 "xyz.openbmc_project.State.Boot.Progress"; 200 // TODO Need to change host instance if multiple instead "0" 201 constexpr auto hostStateObjPath = "/xyz/openbmc_project/state/host0"; 202 return getStateValue<BootProgress>(bootProgressInterface, hostStateObjPath, 203 "BootProgress"); 204 } 205 206 /** 207 * @brief Check whether host is running 208 * 209 * @return true if the host running else false. 210 * 211 * @throws std::runtime_error - If getting the boot progress failed 212 */ 213 inline bool isHostRunning() 214 { 215 // TODO #ibm-openbmc/dev/2858 Revisit the method for finding whether host 216 // is running. 217 BootProgress bootProgressStatus = getBootProgress(); 218 if ((bootProgressStatus == BootProgress::SystemInitComplete) || 219 (bootProgressStatus == BootProgress::SystemSetup) || 220 (bootProgressStatus == BootProgress::OSStart) || 221 (bootProgressStatus == BootProgress::OSRunning) || 222 (bootProgressStatus == BootProgress::PCIInit)) 223 { 224 return true; 225 } 226 return false; 227 } 228 229 inline void extractOriginatorProperties(phosphor::dump::DumpCreateParams params, 230 std::string& originatorId, 231 originatorTypes& originatorType) 232 { 233 using InvalidArgument = 234 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 235 using Argument = xyz::openbmc_project::Common::InvalidArgument; 236 using CreateParametersXYZ = 237 sdbusplus::xyz::openbmc_project::Dump::server::Create::CreateParameters; 238 239 auto iter = params.find( 240 sdbusplus::xyz::openbmc_project::Dump::server::Create:: 241 convertCreateParametersToString(CreateParametersXYZ::OriginatorId)); 242 if (iter == params.end()) 243 { 244 lg2::info("OriginatorId is not provided"); 245 } 246 else 247 { 248 try 249 { 250 originatorId = std::get<std::string>(iter->second); 251 } 252 catch (const std::bad_variant_access& e) 253 { 254 // Exception will be raised if the input is not string 255 lg2::error("An invalid originatorId passed. It should be a string, " 256 "errormsg: {ERROR}", 257 "ERROR", e); 258 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_ID"), 259 Argument::ARGUMENT_VALUE("INVALID INPUT")); 260 } 261 } 262 263 iter = params.find(sdbusplus::xyz::openbmc_project::Dump::server::Create:: 264 convertCreateParametersToString( 265 CreateParametersXYZ::OriginatorType)); 266 if (iter == params.end()) 267 { 268 lg2::info("OriginatorType is not provided. Replacing the string " 269 "with the default value"); 270 originatorType = originatorTypes::Internal; 271 } 272 else 273 { 274 try 275 { 276 std::string type = std::get<std::string>(iter->second); 277 originatorType = sdbusplus::xyz::openbmc_project::Common::server:: 278 OriginatedBy::convertOriginatorTypesFromString(type); 279 } 280 catch (const std::bad_variant_access& e) 281 { 282 // Exception will be raised if the input is not string 283 lg2::error("An invalid originatorType passed, errormsg: {ERROR}", 284 "ERROR", e); 285 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ORIGINATOR_TYPE"), 286 Argument::ARGUMENT_VALUE("INVALID INPUT")); 287 } 288 } 289 } 290 291 /** 292 * @brief Check whether host is quiesced 293 * 294 * @return true if the host is quiesced else false. 295 * 296 * @throws std::runtime_error - If getting the state failed 297 */ 298 inline bool isHostQuiesced() 299 { 300 return (getHostState() == HostState::Quiesced); 301 } 302 303 } // namespace dump 304 } // namespace phosphor 305