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