blob: 54a182acea2f34b391c7405115bd978e7fe9ac9a [file] [log] [blame]
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <sdbusplus/bus.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Control/Host/server.hpp>
#include <config.h>
using namespace std::literals;
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Control::server;
// Required strings for sending the msg to check on host
constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
constexpr auto CONTROL_HOST_PATH = "/xyz/openbmc_project/control/host0";
constexpr auto CONTROL_HOST_INTERFACE = "xyz.openbmc_project.Control.Host";
bool cmdDone = false;
bool hostRunning = false;
// Function called on host control signals
static int hostControlSignal(sd_bus_message* msg, void* userData,
sd_bus_error* retError)
{
std::string cmdCompleted{};
std::string cmdStatus{};
auto sdPlusMsg = sdbusplus::message::message(msg);
sdPlusMsg.read(cmdCompleted, cmdStatus);
log<level::DEBUG>("Host control signal values",
entry("COMMAND=%s", cmdCompleted.c_str()),
entry("STATUS=%s", cmdStatus.c_str()));
// Verify it's the command this code is interested in and then check status
if (Host::convertCommandFromString(cmdCompleted) ==
Host::Command::Heartbeat)
{
cmdDone = true;
if (Host::convertResultFromString(cmdStatus) == Host::Result::Success)
{
hostRunning = true;
}
}
return 0;
}
// Send hearbeat to host to determine if it's running
void sendHeartbeat(sdbusplus::bus::bus& bus)
{
auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
MAPPER_INTERFACE, "GetObject");
mapper.append(CONTROL_HOST_PATH,
std::vector<std::string>({CONTROL_HOST_INTERFACE}));
auto mapperResponseMsg = bus.call(mapper);
if (mapperResponseMsg.is_method_error())
{
log<level::ERR>("Error in mapper call for control host");
// TODO openbmc/openbmc#851 - Once available, throw returned error
throw std::runtime_error("Error in mapper call for control host");
}
std::map<std::string, std::vector<std::string>> mapperResponse;
mapperResponseMsg.read(mapperResponse);
if (mapperResponse.empty())
{
log<level::ERR>("Error reading mapper resp for control host");
// TODO openbmc/openbmc#851 - Once available, throw returned error
throw std::runtime_error("Error reading mapper resp for control host");
}
const auto& host = mapperResponse.begin()->first;
auto method = bus.new_method_call(host.c_str(), CONTROL_HOST_PATH,
CONTROL_HOST_INTERFACE, "Execute");
method.append(convertForMessage(Host::Command::Heartbeat).c_str());
auto reply = bus.call(method);
if (reply.is_method_error())
{
log<level::ERR>("Error in call to control host Execute");
throw std::runtime_error("Error in call to control host Execute");
}
return;
}
int main(int argc, char* argv[])
{
log<level::INFO>("Check if host is running");
auto bus = sdbusplus::bus::new_default();
auto s = "type='signal',member='CommandComplete',path='"s +
CONTROL_HOST_PATH + "',interface='" + CONTROL_HOST_INTERFACE + "'";
// Setup Signal Handler
sdbusplus::bus::match::match hostControlSignals(bus, s.c_str(),
hostControlSignal, nullptr);
sendHeartbeat(bus);
// Wait for signal
while (!cmdDone)
{
bus.process_discard();
if (cmdDone)
break;
bus.wait();
}
// If host running then create file
if (hostRunning)
{
log<level::INFO>("Host is running!");
// Create file for host instance and create in filesystem to indicate
// to services that host is running
auto size = std::snprintf(nullptr, 0, HOST_RUNNING_FILE, 0);
size++; // null
std::unique_ptr<char[]> buf(new char[size]);
std::snprintf(buf.get(), size, HOST_RUNNING_FILE, 0);
std::ofstream outfile(buf.get());
outfile.close();
}
else
{
log<level::INFO>("Host is not running!");
}
return 0;
}