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