blob: efb7abd6ab8f45d2c14a49b909df59e40ea6343c [file] [log] [blame]
#include "utils.hpp"
#include <systemd/sd-event.h>
#include <unistd.h>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/bus.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
#include <xyz/openbmc_project/State/Host/server.hpp>
#include <string>
namespace open_power
{
namespace occ
{
namespace utils
{
// For throwing exceptions
using namespace phosphor::logging;
using InternalFailure =
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
Progress::ProgressStages;
constexpr auto HOST_STATE_OBJ_PATH = "/xyz/openbmc_project/state/host0";
const std::string getService(const std::string& path,
const std::string& interface)
{
using InterfaceList = std::vector<std::string>;
std::map<std::string, std::vector<std::string>> mapperResponse;
auto& bus = getBus();
auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
MAPPER_IFACE, "GetObject");
mapper.append(path, InterfaceList({interface}));
auto mapperResponseMsg = bus.call(mapper);
mapperResponseMsg.read(mapperResponse);
if (mapperResponse.empty())
{
lg2::error("ERROR reading mapper response: path={PATH}, I/F={INTF}",
"PATH", path, "INTF", interface);
elog<InternalFailure>();
}
// the value here will be the service name
return mapperResponse.cbegin()->first;
}
const PropertyValue getProperty(const std::string& objectPath,
const std::string& interface,
const std::string& propertyName)
{
PropertyValue value{};
auto& bus = getBus();
auto service = getService(objectPath, interface);
if (service.empty())
{
return value;
}
auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
DBUS_PROPERTY_IFACE, "Get");
method.append(interface, propertyName);
auto reply = bus.call(method);
reply.read(value);
return value;
}
/**
* @brief Sets a given object's property value
*
* @param[in] objectPath - Name of the object containing the property
* @param[in] interface - Interface name containing the property
* @param[in] propertyName - Property name
* @param[in] value - Property value
*/
void setProperty(const std::string& objectPath, const std::string& interface,
const std::string& propertyName, PropertyValue&& value)
{
using namespace std::literals::string_literals;
PropertyValue varValue(std::forward<PropertyValue>(value));
try
{
auto& bus = getBus();
auto service = getService(objectPath, interface);
if (service.empty())
{
return;
}
auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
DBUS_PROPERTY_IFACE, "Set");
method.append(interface, propertyName, varValue);
auto reply = bus.call(method);
if (reply.is_method_error())
{
lg2::error("util::setProperty: Failed to set property {PROP}",
"PROP", propertyName);
}
}
catch (const std::exception& e)
{
auto error = errno;
lg2::error("setProperty: failed to Set {PROP}, errno={ERR}, what={MSG}",
"PROP", propertyName, "ERR", error, "PROP", e.what());
}
}
std::vector<std::string> getSubtreePaths(
const std::vector<std::string>& interfaces, const std::string& path)
{
std::vector<std::string> paths;
auto& bus = getBus();
auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
MAPPER_IFACE, "GetSubTreePaths");
method.append(path, 0, interfaces);
auto reply = bus.call(method);
reply.read(paths);
return paths;
}
// Get the service and object path for an interface
std::string getServiceUsingSubTree(const std::string& interface,
std::string& path)
{
using Path = std::string;
using Intf = std::string;
using Serv = std::string;
using Intfs = std::vector<Intf>;
using Objects = std::map<Path, std::map<Serv, Intfs>>;
Serv service;
Objects rspObjects;
auto& bus = getBus();
auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
MAPPER_IFACE, "GetSubTree");
method.append(path, 0, std::vector{interface});
auto mapperResponseMsg = bus.call(method);
mapperResponseMsg.read(rspObjects);
if (rspObjects.empty())
{
lg2::error(
"util::getServiceUsingSubTree: Failed getSubTree({PATH},0,{INTF})",
"PATH", path, "INTF", interface);
}
else
{
path = rspObjects.begin()->first;
if (!rspObjects.begin()->second.empty())
{
service = rspObjects.begin()->second.begin()->first;
}
else
{
lg2::error(
"getServiceUsingSubTree: service not found for interface {INTF} (path={PATH})",
"INTF", interface, "PATH", path);
}
}
return service;
}
std::string getStateValue(const std::string& intf, const std::string& objPath,
const std::string& state)
{
std::string stateVal;
try
{
auto& bus = getBus();
auto service = getService(objPath, intf);
if (service.empty())
{
throw std::runtime_error("getStateValue: Failed to get service");
}
auto method =
bus.new_method_call(service.c_str(), objPath.c_str(),
"org.freedesktop.DBus.Properties", "Get");
method.append(intf, state);
auto reply = bus.call(method);
std::variant<std::string> propertyVal;
reply.read(propertyVal);
stateVal = std::get<std::string>(propertyVal);
}
catch (const sdbusplus::exception_t& e)
{
lg2::error("D-Bus call exception, OBJPATH({PATH}), "
"INTERFACE({INTF}), PROPERTY({PROP}) EXCEPTION({ERR})",
"PATH", objPath, "INTF", intf, "PROP", state, "ERR",
e.what());
throw std::runtime_error("Failed to get host state property");
}
catch (const std::bad_variant_access& e)
{
lg2::error(
"Exception raised while read host state({STATE}) property "
"value, OBJPATH({PATH}), INTERFACE({INTF}), EXCEPTION({ERR})",
"STATE", state, "PATH", objPath, "INTF", intf, "ERR", e.what());
throw std::runtime_error("Failed to get host state property");
}
return stateVal;
}
BootProgress getBootProgress()
{
BootProgress bootProgessStage;
constexpr auto bootProgressInterface =
"xyz.openbmc_project.State.Boot.Progress";
std::string value = getStateValue(bootProgressInterface,
HOST_STATE_OBJ_PATH, "BootProgress");
bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
Progress::convertProgressStagesFromString(value);
return bootProgessStage;
}
bool isHostRunning()
{
BootProgress bootProgressStatus = getBootProgress();
if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
(bootProgressStatus == BootProgress::SystemSetup) ||
(bootProgressStatus == BootProgress::OSRunning))
{
return true;
}
return false;
}
} // namespace utils
} // namespace occ
} // namespace open_power