#include "watchdog_service.hpp" #include #include #include #include #include #include #include #include #include #include #include using phosphor::logging::elog; using phosphor::logging::entry; using phosphor::logging::level; using phosphor::logging::log; using sdbusplus::message::variant_ns::get; using sdbusplus::message::variant_ns::variant; using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; using sdbusplus::xyz::openbmc_project::State::server::convertForMessage; using sdbusplus::xyz::openbmc_project::State::server::Watchdog; static constexpr char wd_path[] = "/xyz/openbmc_project/watchdog/host0"; static constexpr char wd_intf[] = "xyz.openbmc_project.State.Watchdog"; static constexpr char prop_intf[] = "org.freedesktop.DBus.Properties"; ipmi::ServiceCache WatchdogService::wd_service(wd_intf, wd_path); WatchdogService::WatchdogService() : bus(ipmid_get_sd_bus_connection()) { } void WatchdogService::resetTimeRemaining(bool enableWatchdog) { bool wasValid = wd_service.isValid(bus); auto request = wd_service.newMethodCall(bus, wd_intf, "ResetTimeRemaining"); request.append(enableWatchdog); auto response = bus.call(request); if (response.is_method_error()) { wd_service.invalidate(); if (wasValid) { // Retry the request once in case the cached service was stale return resetTimeRemaining(enableWatchdog); } log( "WatchdogService: Method error resetting time remaining", entry("ENABLE_WATCHDOG=%d", !!enableWatchdog)); elog(); } } WatchdogService::Properties WatchdogService::getProperties() { bool wasValid = wd_service.isValid(bus); auto request = wd_service.newMethodCall(bus, prop_intf, "GetAll"); request.append(wd_intf); auto response = bus.call(request); if (response.is_method_error()) { wd_service.invalidate(); if (wasValid) { // Retry the request once in case the cached service was stale return getProperties(); } log("WatchdogService: Method error getting properties"); elog(); } try { std::map> properties; response.read(properties); Properties wd_prop; wd_prop.initialized = get(properties.at("Initialized")); wd_prop.enabled = get(properties.at("Enabled")); wd_prop.expireAction = Watchdog::convertActionFromString( get(properties.at("ExpireAction"))); wd_prop.timerUse = Watchdog::convertTimerUseFromString( get(properties.at("CurrentTimerUse"))); wd_prop.interval = get(properties.at("Interval")); wd_prop.timeRemaining = get(properties.at("TimeRemaining")); return wd_prop; } catch (const std::exception& e) { log("WatchdogService: Decode error in get properties", entry("ERROR=%s", e.what()), entry("REPLY_SIG=%s", response.get_signature())); elog(); } // Needed instead of elog() since the compiler can't // deduce the that elog<>() always throws throw std::runtime_error( "WatchdogService: Should not reach end of getProperties"); } template T WatchdogService::getProperty(const std::string& key) { bool wasValid = wd_service.isValid(bus); auto request = wd_service.newMethodCall(bus, prop_intf, "Get"); request.append(wd_intf, key); auto response = bus.call(request); if (response.is_method_error()) { wd_service.invalidate(); if (wasValid) { // Retry the request once in case the cached service was stale return getProperty(key); } log("WatchdogService: Method error getting property", entry("PROPERTY=%s", key.c_str())); elog(); } try { variant value; response.read(value); return get(value); } catch (const std::exception& e) { log("WatchdogService: Decode error in get property", entry("PROPERTY=%s", key.c_str()), entry("ERROR=%s", e.what()), entry("REPLY_SIG=%s", response.get_signature())); elog(); } // Needed instead of elog() since the compiler can't // deduce the that elog<>() always throws throw std::runtime_error( "WatchdogService: Should not reach end of getProperty"); } template void WatchdogService::setProperty(const std::string& key, const T& val) { bool wasValid = wd_service.isValid(bus); auto request = wd_service.newMethodCall(bus, prop_intf, "Set"); request.append(wd_intf, key, variant(val)); auto response = bus.call(request); if (response.is_method_error()) { wd_service.invalidate(); if (wasValid) { // Retry the request once in case the cached service was stale return setProperty(key, val); } log("WatchdogService: Method error setting property", entry("PROPERTY=%s", key.c_str())); elog(); } } bool WatchdogService::getInitialized() { return getProperty("Initialized"); } void WatchdogService::setInitialized(bool initialized) { setProperty("Initialized", initialized); } void WatchdogService::setEnabled(bool enabled) { setProperty("Enabled", enabled); } void WatchdogService::setExpireAction(Action expireAction) { setProperty("ExpireAction", convertForMessage(expireAction)); } void WatchdogService::setTimerUse(TimerUse timerUse) { setProperty("CurrentTimerUse", convertForMessage(timerUse)); } void WatchdogService::setInterval(uint64_t interval) { setProperty("Interval", interval); } void WatchdogService::setTimeRemaining(uint64_t timeRemaining) { setProperty("TimeRemaining", timeRemaining); }