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