#include #include #include #include #include #include #include #include #include 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("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({CONTROL_HOST_INTERFACE})); auto mapperResponseMsg = bus.call(mapper); if (mapperResponseMsg.is_method_error()) { log("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> mapperResponse; mapperResponseMsg.read(mapperResponse); if (mapperResponse.empty()) { log("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("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("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("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 buf(new char[size]); std::snprintf(buf.get(),size,HOST_RUNNING_FILE,0); std::ofstream outfile(buf.get()); outfile.close(); } else { log("Host is not running!"); } return 0; }