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