1 #include <iostream> 2 #include <map> 3 #include <string> 4 #include <config.h> 5 #include <systemd/sd-bus.h> 6 #include <sdbusplus/server.hpp> 7 #include <phosphor-logging/log.hpp> 8 #include <phosphor-logging/elog-errors.hpp> 9 #include "host_state_manager.hpp" 10 #include "settings.hpp" 11 #include "xyz/openbmc_project/Common/error.hpp" 12 #include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp" 13 14 namespace phosphor 15 { 16 namespace state 17 { 18 namespace manager 19 { 20 21 using namespace phosphor::logging; 22 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 23 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server; 24 25 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 26 constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 27 constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 28 29 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; 30 31 constexpr auto HOST_PATH = "/xyz/openbmc_project/state/host0"; 32 33 std::string getService(sdbusplus::bus::bus& bus, std::string path, 34 std::string interface) 35 { 36 auto mapper = bus.new_method_call(MAPPER_BUSNAME, 37 MAPPER_PATH, 38 MAPPER_INTERFACE, 39 "GetObject"); 40 41 mapper.append(path, std::vector<std::string>({interface})); 42 auto mapperResponseMsg = bus.call(mapper); 43 44 if (mapperResponseMsg.is_method_error()) 45 { 46 log<level::ERR>("Error in mapper call", 47 entry("PATH=%s", path.c_str()), 48 entry("INTERFACE=%s", interface.c_str())); 49 throw std::runtime_error("Error in mapper call"); 50 } 51 52 std::map<std::string, std::vector<std::string>> mapperResponse; 53 mapperResponseMsg.read(mapperResponse); 54 if (mapperResponse.empty()) 55 { 56 log<level::ERR>("Error reading mapper response", 57 entry("PATH=%s", path.c_str()), 58 entry("INTERFACE=%s", interface.c_str())); 59 throw std::runtime_error("Error reading mapper response"); 60 } 61 62 return mapperResponse.begin()->first; 63 } 64 65 std::string getProperty(sdbusplus::bus::bus& bus, std::string path, 66 std::string interface, std::string propertyName) 67 { 68 sdbusplus::message::variant<std::string> property; 69 std::string service = getService(bus, path, interface); 70 71 auto method = bus.new_method_call(service.c_str(), 72 path.c_str(), 73 PROPERTY_INTERFACE, 74 "Get"); 75 76 method.append(interface, propertyName); 77 auto reply = bus.call(method); 78 79 if (reply.is_method_error()) 80 { 81 log<level::ERR>("Error in property Get", 82 entry("PROPERTY=%s", propertyName.c_str())); 83 throw std::runtime_error("Error in property Get"); 84 } 85 86 reply.read(property); 87 88 if (sdbusplus::message::variant_ns::get<std::string>(property).empty()) 89 { 90 log<level::ERR>("Error reading property response", 91 entry("PROPERTY=%s", propertyName.c_str())); 92 throw std::runtime_error("Error reading property response"); 93 } 94 95 return sdbusplus::message::variant_ns::get<std::string>(property); 96 } 97 98 void setProperty(sdbusplus::bus::bus& bus, std::string path, 99 std::string interface, std::string property, std::string value) 100 { 101 sdbusplus::message::variant<std::string> variantValue = value; 102 std::string service = getService(bus, path, interface); 103 104 auto method = bus.new_method_call(service.c_str(), 105 path.c_str(), 106 PROPERTY_INTERFACE, 107 "Set"); 108 109 method.append(interface, property, variantValue); 110 bus.call_noreply(method); 111 112 return; 113 } 114 115 } // namespace manager 116 } // namespace state 117 } // namepsace phosphor 118 119 int main() 120 { 121 using namespace phosphor::logging; 122 123 auto bus = sdbusplus::bus::new_default(); 124 125 using namespace settings; 126 Objects settings(bus); 127 128 using namespace phosphor::state::manager; 129 namespace server = sdbusplus::xyz::openbmc_project::State::server; 130 131 // This application is only run if chassis power is off 132 133 auto method = 134 bus.new_method_call( 135 settings.service(settings.powerRestorePolicy, 136 powerRestoreIntf).c_str(), 137 settings.powerRestorePolicy.c_str(), 138 "org.freedesktop.DBus.Properties", 139 "Get"); 140 method.append(powerRestoreIntf, "PowerRestorePolicy"); 141 auto reply = bus.call(method); 142 if (reply.is_method_error()) 143 { 144 log<level::ERR>("Error in PowerRestorePolicy Get"); 145 elog<InternalFailure>(); 146 } 147 148 sdbusplus::message::variant<std::string> result; 149 reply.read(result); 150 auto powerPolicy = result.get<std::string>(); 151 152 log<level::INFO>("Host power is off, checking power policy", 153 entry("POWER_POLICY=%s", powerPolicy.c_str())); 154 155 if (RestorePolicy::Policy::AlwaysOn == 156 RestorePolicy::convertPolicyFromString(powerPolicy)) 157 { 158 log<level::INFO>("power_policy=ALWAYS_POWER_ON, powering host on"); 159 setProperty(bus, HOST_PATH, HOST_BUSNAME, 160 "RequestedHostTransition", 161 convertForMessage(server::Host::Transition::On)); 162 } 163 else if(RestorePolicy::Policy::Restore == 164 RestorePolicy::convertPolicyFromString(powerPolicy)) 165 { 166 log<level::INFO>("power_policy=RESTORE, restoring last state"); 167 168 // Read last requested state and re-request it to execute it 169 auto hostReqState = getProperty(bus, HOST_PATH, 170 HOST_BUSNAME, 171 "RequestedHostTransition"); 172 setProperty(bus, HOST_PATH, HOST_BUSNAME, 173 "RequestedHostTransition", 174 hostReqState); 175 } 176 177 return 0; 178 } 179