blob: 54a182acea2f34b391c7405115bd978e7fe9ac9a [file] [log] [blame]
Andrew Geisslerb09463d2017-03-24 15:55:17 -05001#include <cstdlib>
Andrew Geissler0971dea2017-03-28 14:32:40 -05002#include <unistd.h>
Andrew Geissler07d0ed52017-03-28 15:44:18 -05003#include <iostream>
4#include <fstream>
5#include <cstdio>
Andrew Geisslerb09463d2017-03-24 15:55:17 -05006#include <sdbusplus/bus.hpp>
7#include <phosphor-logging/log.hpp>
Andrew Geissler0971dea2017-03-28 14:32:40 -05008#include <xyz/openbmc_project/Control/Host/server.hpp>
Andrew Geissler07d0ed52017-03-28 15:44:18 -05009#include <config.h>
Andrew Geisslerb09463d2017-03-24 15:55:17 -050010
Andrew Geisslereeaccf82017-03-28 15:23:27 -050011using namespace std::literals;
Andrew Geisslerb09463d2017-03-24 15:55:17 -050012using namespace phosphor::logging;
Andrew Geissler0971dea2017-03-28 14:32:40 -050013using namespace sdbusplus::xyz::openbmc_project::Control::server;
14
Andrew Geisslereeaccf82017-03-28 15:23:27 -050015// Required strings for sending the msg to check on host
16constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
17constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
18constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
19constexpr auto CONTROL_HOST_PATH = "/xyz/openbmc_project/control/host0";
20constexpr auto CONTROL_HOST_INTERFACE = "xyz.openbmc_project.Control.Host";
Andrew Geissler0971dea2017-03-28 14:32:40 -050021
Andrew Geissler58a18012018-01-19 19:36:05 -080022bool cmdDone = false;
Andrew Geissler0971dea2017-03-28 14:32:40 -050023bool hostRunning = false;
24
25// Function called on host control signals
Andrew Geissler58a18012018-01-19 19:36:05 -080026static int hostControlSignal(sd_bus_message* msg, void* userData,
Andrew Geissler0971dea2017-03-28 14:32:40 -050027 sd_bus_error* retError)
28{
29 std::string cmdCompleted{};
30 std::string cmdStatus{};
31
32 auto sdPlusMsg = sdbusplus::message::message(msg);
33 sdPlusMsg.read(cmdCompleted, cmdStatus);
34
35 log<level::DEBUG>("Host control signal values",
Andrew Geissler58a18012018-01-19 19:36:05 -080036 entry("COMMAND=%s", cmdCompleted.c_str()),
37 entry("STATUS=%s", cmdStatus.c_str()));
Andrew Geissler0971dea2017-03-28 14:32:40 -050038
39 // Verify it's the command this code is interested in and then check status
Andrew Geissler58a18012018-01-19 19:36:05 -080040 if (Host::convertCommandFromString(cmdCompleted) ==
41 Host::Command::Heartbeat)
Andrew Geissler0971dea2017-03-28 14:32:40 -050042 {
43 cmdDone = true;
44
Andrew Geissler58a18012018-01-19 19:36:05 -080045 if (Host::convertResultFromString(cmdStatus) == Host::Result::Success)
Andrew Geissler0971dea2017-03-28 14:32:40 -050046 {
47 hostRunning = true;
48 }
49 }
50
51 return 0;
52}
Andrew Geisslerb09463d2017-03-24 15:55:17 -050053
Andrew Geisslereeaccf82017-03-28 15:23:27 -050054// Send hearbeat to host to determine if it's running
55void sendHeartbeat(sdbusplus::bus::bus& bus)
56{
Andrew Geissler58a18012018-01-19 19:36:05 -080057 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
58 MAPPER_INTERFACE, "GetObject");
Andrew Geisslereeaccf82017-03-28 15:23:27 -050059
60 mapper.append(CONTROL_HOST_PATH,
61 std::vector<std::string>({CONTROL_HOST_INTERFACE}));
62 auto mapperResponseMsg = bus.call(mapper);
63
64 if (mapperResponseMsg.is_method_error())
65 {
66 log<level::ERR>("Error in mapper call for control host");
67 // TODO openbmc/openbmc#851 - Once available, throw returned error
68 throw std::runtime_error("Error in mapper call for control host");
69 }
70
71 std::map<std::string, std::vector<std::string>> mapperResponse;
72 mapperResponseMsg.read(mapperResponse);
73 if (mapperResponse.empty())
74 {
75 log<level::ERR>("Error reading mapper resp for control host");
76 // TODO openbmc/openbmc#851 - Once available, throw returned error
77 throw std::runtime_error("Error reading mapper resp for control host");
78 }
79
80 const auto& host = mapperResponse.begin()->first;
81
Andrew Geissler58a18012018-01-19 19:36:05 -080082 auto method = bus.new_method_call(host.c_str(), CONTROL_HOST_PATH,
83 CONTROL_HOST_INTERFACE, "Execute");
Andrew Geisslereeaccf82017-03-28 15:23:27 -050084 method.append(convertForMessage(Host::Command::Heartbeat).c_str());
85
86 auto reply = bus.call(method);
87 if (reply.is_method_error())
88 {
89 log<level::ERR>("Error in call to control host Execute");
90 throw std::runtime_error("Error in call to control host Execute");
91 }
92
93 return;
94}
95
Andrew Geissler58a18012018-01-19 19:36:05 -080096int main(int argc, char* argv[])
Andrew Geisslerb09463d2017-03-24 15:55:17 -050097{
98 log<level::INFO>("Check if host is running");
99
Andrew Geissler0971dea2017-03-28 14:32:40 -0500100 auto bus = sdbusplus::bus::new_default();
Andrew Geisslerb09463d2017-03-24 15:55:17 -0500101
Andrew Geisslereeaccf82017-03-28 15:23:27 -0500102 auto s = "type='signal',member='CommandComplete',path='"s +
Andrew Geissler58a18012018-01-19 19:36:05 -0800103 CONTROL_HOST_PATH + "',interface='" + CONTROL_HOST_INTERFACE + "'";
Andrew Geisslereeaccf82017-03-28 15:23:27 -0500104
Andrew Geissler0971dea2017-03-28 14:32:40 -0500105 // Setup Signal Handler
Andrew Geissler58a18012018-01-19 19:36:05 -0800106 sdbusplus::bus::match::match hostControlSignals(bus, s.c_str(),
107 hostControlSignal, nullptr);
Andrew Geissler0971dea2017-03-28 14:32:40 -0500108
Andrew Geisslereeaccf82017-03-28 15:23:27 -0500109 sendHeartbeat(bus);
Andrew Geisslerb09463d2017-03-24 15:55:17 -0500110
111 // Wait for signal
Andrew Geissler58a18012018-01-19 19:36:05 -0800112 while (!cmdDone)
Andrew Geissler0971dea2017-03-28 14:32:40 -0500113 {
114 bus.process_discard();
Andrew Geissler58a18012018-01-19 19:36:05 -0800115 if (cmdDone)
116 break;
Andrew Geissler0971dea2017-03-28 14:32:40 -0500117 bus.wait();
118 }
Andrew Geisslerb09463d2017-03-24 15:55:17 -0500119
120 // If host running then create file
Andrew Geissler58a18012018-01-19 19:36:05 -0800121 if (hostRunning)
Andrew Geissler0971dea2017-03-28 14:32:40 -0500122 {
Andrew Geissler0971dea2017-03-28 14:32:40 -0500123 log<level::INFO>("Host is running!");
Andrew Geissler07d0ed52017-03-28 15:44:18 -0500124 // Create file for host instance and create in filesystem to indicate
125 // to services that host is running
Andrew Geissler58a18012018-01-19 19:36:05 -0800126 auto size = std::snprintf(nullptr, 0, HOST_RUNNING_FILE, 0);
Andrew Geissler0135bd52017-05-09 13:54:10 -0500127 size++; // null
128 std::unique_ptr<char[]> buf(new char[size]);
Andrew Geissler58a18012018-01-19 19:36:05 -0800129 std::snprintf(buf.get(), size, HOST_RUNNING_FILE, 0);
Andrew Geissler07d0ed52017-03-28 15:44:18 -0500130 std::ofstream outfile(buf.get());
131 outfile.close();
132 }
133 else
134 {
135 log<level::INFO>("Host is not running!");
Andrew Geissler0971dea2017-03-28 14:32:40 -0500136 }
Andrew Geisslerb09463d2017-03-24 15:55:17 -0500137
138 return 0;
139}