1 #pragma once 2 3 #include <string> 4 #include <functional> 5 #include <experimental/filesystem> 6 #include <cereal/access.hpp> 7 #include <cereal/cereal.hpp> 8 #include <sdbusplus/bus.hpp> 9 #include <phosphor-logging/log.hpp> 10 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp> 11 #include <xyz/openbmc_project/Control/Boot/RebootAttempts/server.hpp> 12 #include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp> 13 #include "xyz/openbmc_project/State/Host/server.hpp" 14 #include "settings.hpp" 15 #include "config.h" 16 17 namespace phosphor 18 { 19 namespace state 20 { 21 namespace manager 22 { 23 24 using HostInherit = sdbusplus::server::object::object< 25 sdbusplus::xyz::openbmc_project::State::server::Host, 26 sdbusplus::xyz::openbmc_project::State::Boot::server::Progress, 27 sdbusplus::xyz::openbmc_project::Control::Boot::server::RebootAttempts, 28 sdbusplus::xyz::openbmc_project::State::OperatingSystem::server::Status>; 29 30 using namespace phosphor::logging; 31 32 namespace sdbusRule = sdbusplus::bus::match::rules; 33 namespace fs = std::experimental::filesystem; 34 35 /** @class Host 36 * @brief OpenBMC host state management implementation. 37 * @details A concrete implementation for xyz.openbmc_project.State.Host 38 * DBus API. 39 */ 40 class Host : public HostInherit 41 { 42 public: 43 /** @brief Constructs Host State Manager 44 * 45 * @note This constructor passes 'true' to the base class in order to 46 * defer dbus object registration until we can run 47 * determineInitialState() and set our properties 48 * 49 * @param[in] bus - The Dbus bus object 50 * @param[in] busName - The Dbus name to own 51 * @param[in] objPath - The Dbus object path 52 */ 53 Host(sdbusplus::bus::bus& bus, const char* busName, const char* objPath) : 54 HostInherit(bus, objPath, true), bus(bus), 55 systemdSignals( 56 bus, 57 sdbusRule::type::signal() + sdbusRule::member("JobRemoved") + 58 sdbusRule::path("/org/freedesktop/systemd1") + 59 sdbusRule::interface("org.freedesktop.systemd1.Manager"), 60 std::bind(std::mem_fn(&Host::sysStateChange), this, 61 std::placeholders::_1)), 62 settings(bus) 63 { 64 // Enable systemd signals 65 subscribeToSystemdSignals(); 66 67 // Will throw exception on fail 68 determineInitialState(); 69 70 attemptsLeft(BOOT_COUNT_MAX_ALLOWED); 71 72 // We deferred this until we could get our property correct 73 this->emit_object_added(); 74 } 75 76 /** @brief Set value of HostTransition */ 77 Transition requestedHostTransition(Transition value) override; 78 79 /** @brief Set Value for boot progress */ 80 ProgressStages bootProgress(ProgressStages value) override; 81 82 /** @brief Set Value for Operating System Status */ 83 OSStatus operatingSystemState(OSStatus value) override; 84 85 /** @brief Set value of CurrentHostState */ 86 HostState currentHostState(HostState value) override; 87 88 /** 89 * @brief Set host reboot count to default 90 * 91 * OpenBMC software controls the number of allowed reboot attempts so 92 * any external set request of this property will be overridden by 93 * this function and set to the default. 94 * 95 * The only code responsible for decrementing the boot count resides 96 * within this process and that will use the sub class interface 97 * directly 98 * 99 * @param[in] value - Reboot count value, will be ignored 100 * 101 * @return Default number of reboot attempts left 102 */ 103 uint32_t attemptsLeft(uint32_t value) override 104 { 105 log<level::DEBUG>("External request to reset reboot count"); 106 return (sdbusplus::xyz::openbmc_project::Control::Boot::server:: 107 RebootAttempts::attemptsLeft(BOOT_COUNT_MAX_ALLOWED)); 108 } 109 110 private: 111 /** 112 * @brief subscribe to the systemd signals 113 * 114 * This object needs to capture when it's systemd targets complete 115 * so it can keep it's state updated 116 * 117 **/ 118 void subscribeToSystemdSignals(); 119 120 /** 121 * @brief Determine initial host state and set internally 122 * 123 * @return Will throw exceptions on failure 124 **/ 125 void determineInitialState(); 126 127 /** @brief Execute the transition request 128 * 129 * This function assumes the state has been validated and the host 130 * is in an appropriate state for the transition to be started. 131 * 132 * @param[in] tranReq - Transition requested 133 */ 134 void executeTransition(Transition tranReq); 135 136 /** 137 * @brief Determine if target is active 138 * 139 * This function determines if the target is active and 140 * helps prevent misleading log recorded states. 141 * 142 * @param[in] target - Target string to check on 143 * 144 * @return boolean corresponding to state active 145 **/ 146 bool stateActive(const std::string& target); 147 148 /** 149 * @brief Determine if auto reboot flag is set 150 * 151 * @return boolean corresponding to current auto_reboot setting 152 **/ 153 bool isAutoReboot(); 154 155 /** @brief Check if systemd state change is relevant to this object 156 * 157 * Instance specific interface to handle the detected systemd state 158 * change 159 * 160 * @param[in] msg - Data associated with subscribed signal 161 * 162 */ 163 void sysStateChange(sdbusplus::message::message& msg); 164 165 /** @brief Decrement reboot count 166 * 167 * This is used internally to this application to decrement the boot 168 * count on each boot attempt. The host will use the external 169 * attemptsLeft() interface to reset the count when a boot is successful 170 * 171 * @return number of reboot count attempts left 172 */ 173 uint32_t decrementRebootCount(); 174 175 // Allow cereal class access to allow these next two function to be 176 // private 177 friend class cereal::access; 178 179 /** @brief Function required by Cereal to perform serialization. 180 * 181 * @tparam Archive - Cereal archive type (binary in our case). 182 * @param[in] archive - reference to Cereal archive. 183 * @param[in] version - Class version that enables handling 184 * a serialized data across code levels 185 */ 186 template <class Archive> 187 void save(Archive& archive, const std::uint32_t version) const 188 { 189 archive(convertForMessage(sdbusplus::xyz::openbmc_project::State:: 190 server::Host::requestedHostTransition()), 191 convertForMessage(sdbusplus::xyz::openbmc_project::State::Boot:: 192 server::Progress::bootProgress()), 193 convertForMessage( 194 sdbusplus::xyz::openbmc_project::State::OperatingSystem:: 195 server::Status::operatingSystemState())); 196 } 197 198 /** @brief Function required by Cereal to perform deserialization. 199 * 200 * @tparam Archive - Cereal archive type (binary in our case). 201 * @param[in] archive - reference to Cereal archive. 202 * @param[in] version - Class version that enables handling 203 * a serialized data across code levels 204 */ 205 template <class Archive> 206 void load(Archive& archive, const std::uint32_t version) 207 { 208 std::string reqTranState; 209 std::string bootProgress; 210 std::string osState; 211 archive(reqTranState, bootProgress, osState); 212 auto reqTran = Host::convertTransitionFromString(reqTranState); 213 // When restoring, set the requested state with persistent value 214 // but don't call the override which would execute it 215 sdbusplus::xyz::openbmc_project::State::server::Host:: 216 requestedHostTransition(reqTran); 217 sdbusplus::xyz::openbmc_project::State::Boot::server::Progress:: 218 bootProgress(Host::convertProgressStagesFromString(bootProgress)); 219 sdbusplus::xyz::openbmc_project::State::OperatingSystem::server:: 220 Status::operatingSystemState( 221 Host::convertOSStatusFromString(osState)); 222 } 223 224 /** @brief Serialize and persist requested host state 225 * 226 * @param[in] dir - pathname of file where the serialized host state will 227 * be placed. 228 * 229 * @return fs::path - pathname of persisted requested host state. 230 */ 231 fs::path serialize(const fs::path& dir = fs::path(HOST_STATE_PERSIST_PATH)); 232 233 /** @brief Deserialze a persisted requested host state. 234 * 235 * @param[in] path - pathname of persisted host state file 236 * 237 * @return bool - true if the deserialization was successful, false 238 * otherwise. 239 */ 240 bool deserialize(const fs::path& path); 241 242 /** @brief Persistent sdbusplus DBus bus connection. */ 243 sdbusplus::bus::bus& bus; 244 245 /** @brief Used to subscribe to dbus systemd signals **/ 246 sdbusplus::bus::match_t systemdSignals; 247 248 // Settings objects of interest 249 settings::Objects settings; 250 }; 251 252 } // namespace manager 253 } // namespace state 254 } // namespace phosphor 255