1234a3179SAndrew Geissler #include <phosphor-logging/log.hpp> 2234a3179SAndrew Geissler #include <phosphor-logging/elog-errors.hpp> 3234a3179SAndrew Geissler #include <sdbusplus/server/manager.hpp> 4234a3179SAndrew Geissler #include <sdeventplus/event.hpp> 5234a3179SAndrew Geissler #include <sdbusplus/exception.hpp> 6*769a62f1SAndrew Geissler #include "systemd_target_signal.hpp" 7234a3179SAndrew Geissler #include <xyz/openbmc_project/Common/error.hpp> 8234a3179SAndrew Geissler 9234a3179SAndrew Geissler namespace phosphor 10234a3179SAndrew Geissler { 11234a3179SAndrew Geissler namespace state 12234a3179SAndrew Geissler { 13234a3179SAndrew Geissler namespace manager 14234a3179SAndrew Geissler { 15234a3179SAndrew Geissler 16234a3179SAndrew Geissler using phosphor::logging::elog; 17234a3179SAndrew Geissler using phosphor::logging::entry; 18234a3179SAndrew Geissler using phosphor::logging::level; 19234a3179SAndrew Geissler using phosphor::logging::log; 20234a3179SAndrew Geissler using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 21234a3179SAndrew Geissler 22234a3179SAndrew Geissler void SystemdTargetLogging::logError(const std::string& error, 23234a3179SAndrew Geissler const std::string& result) 24234a3179SAndrew Geissler { 25234a3179SAndrew Geissler auto method = this->bus.new_method_call( 26234a3179SAndrew Geissler "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 27234a3179SAndrew Geissler "xyz.openbmc_project.Logging.Create", "Create"); 28234a3179SAndrew Geissler // Signature is ssa{ss} 29234a3179SAndrew Geissler method.append(error); 30234a3179SAndrew Geissler method.append("xyz.openbmc_project.Logging.Entry.Level.Critical"); 31234a3179SAndrew Geissler method.append(std::array<std::pair<std::string, std::string>, 1>( 32234a3179SAndrew Geissler {std::pair<std::string, std::string>({"SYSTEMD_RESULT", result})})); 33234a3179SAndrew Geissler try 34234a3179SAndrew Geissler { 35234a3179SAndrew Geissler this->bus.call_noreply(method); 36234a3179SAndrew Geissler } 37234a3179SAndrew Geissler catch (const sdbusplus::exception::SdBusError& e) 38234a3179SAndrew Geissler { 39234a3179SAndrew Geissler log<level::ERR>("Failed to create systemd target error", 40234a3179SAndrew Geissler entry("ERROR=%s", error.c_str()), 41234a3179SAndrew Geissler entry("RESULT=%s", result.c_str()), 42234a3179SAndrew Geissler entry("SDBUSERR=%s", e.what())); 43234a3179SAndrew Geissler } 44234a3179SAndrew Geissler } 45234a3179SAndrew Geissler 46234a3179SAndrew Geissler const std::string* SystemdTargetLogging::processError(const std::string& unit, 47234a3179SAndrew Geissler const std::string& result) 48234a3179SAndrew Geissler { 49234a3179SAndrew Geissler auto targetEntry = this->targetData.find(unit); 50234a3179SAndrew Geissler if (targetEntry != this->targetData.end()) 51234a3179SAndrew Geissler { 52234a3179SAndrew Geissler // Check if its result matches any of our monitored errors 53234a3179SAndrew Geissler if (std::find(targetEntry->second.errorsToMonitor.begin(), 54234a3179SAndrew Geissler targetEntry->second.errorsToMonitor.end(), 55234a3179SAndrew Geissler result) != targetEntry->second.errorsToMonitor.end()) 56234a3179SAndrew Geissler { 57234a3179SAndrew Geissler log<level::INFO>("Monitored systemd unit has hit an error", 58234a3179SAndrew Geissler entry("UNIT=%s", unit.c_str()), 59234a3179SAndrew Geissler entry("RESULT=%s", result.c_str())); 60234a3179SAndrew Geissler return (&targetEntry->second.errorToLog); 61234a3179SAndrew Geissler } 62234a3179SAndrew Geissler } 63234a3179SAndrew Geissler return {nullptr}; 64234a3179SAndrew Geissler } 65234a3179SAndrew Geissler 66234a3179SAndrew Geissler void SystemdTargetLogging::systemdUnitChange(sdbusplus::message::message& msg) 67234a3179SAndrew Geissler { 68234a3179SAndrew Geissler uint32_t id; 69234a3179SAndrew Geissler sdbusplus::message::object_path objPath; 70234a3179SAndrew Geissler std::string unit{}; 71234a3179SAndrew Geissler std::string result{}; 72234a3179SAndrew Geissler 73234a3179SAndrew Geissler msg.read(id, objPath, unit, result); 74234a3179SAndrew Geissler 75234a3179SAndrew Geissler // In most cases it will just be success, in which case just return 76234a3179SAndrew Geissler if (result != "done") 77234a3179SAndrew Geissler { 78234a3179SAndrew Geissler const std::string* error = processError(unit, result); 79234a3179SAndrew Geissler 80234a3179SAndrew Geissler // If this is a monitored error then log it 81234a3179SAndrew Geissler if (error) 82234a3179SAndrew Geissler { 83234a3179SAndrew Geissler logError(*error, result); 84234a3179SAndrew Geissler } 85234a3179SAndrew Geissler } 86234a3179SAndrew Geissler return; 87234a3179SAndrew Geissler } 88234a3179SAndrew Geissler 8938605ee2SAndrew Geissler void SystemdTargetLogging::processNameChangeSignal( 9038605ee2SAndrew Geissler sdbusplus::message::message& msg) 9138605ee2SAndrew Geissler { 9238605ee2SAndrew Geissler std::string name; // well-known 9338605ee2SAndrew Geissler std::string old_owner; // unique-name 9438605ee2SAndrew Geissler std::string new_owner; // unique-name 9538605ee2SAndrew Geissler 9638605ee2SAndrew Geissler msg.read(name, old_owner, new_owner); 9738605ee2SAndrew Geissler 9838605ee2SAndrew Geissler // Looking for systemd to be on dbus so we can call it 9938605ee2SAndrew Geissler if (name == "org.freedesktop.systemd1") 10038605ee2SAndrew Geissler { 10138605ee2SAndrew Geissler log<level::INFO>("org.freedesktop.systemd1 is now on dbus"); 10238605ee2SAndrew Geissler subscribeToSystemdSignals(); 10338605ee2SAndrew Geissler } 10438605ee2SAndrew Geissler return; 10538605ee2SAndrew Geissler } 10638605ee2SAndrew Geissler 107234a3179SAndrew Geissler void SystemdTargetLogging::subscribeToSystemdSignals() 108234a3179SAndrew Geissler { 109234a3179SAndrew Geissler auto method = this->bus.new_method_call( 110234a3179SAndrew Geissler "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 111234a3179SAndrew Geissler "org.freedesktop.systemd1.Manager", "Subscribe"); 112234a3179SAndrew Geissler 113234a3179SAndrew Geissler try 114234a3179SAndrew Geissler { 115234a3179SAndrew Geissler this->bus.call(method); 116234a3179SAndrew Geissler } 117234a3179SAndrew Geissler catch (const sdbusplus::exception::SdBusError& e) 118234a3179SAndrew Geissler { 11938605ee2SAndrew Geissler // If error indicates systemd is not on dbus yet then do nothing. 12038605ee2SAndrew Geissler // The systemdNameChangeSignals callback will detect when it is on 12138605ee2SAndrew Geissler // dbus and then call this function again 12238605ee2SAndrew Geissler const std::string noDbus("org.freedesktop.DBus.Error.ServiceUnknown"); 12338605ee2SAndrew Geissler if (noDbus == e.name()) 12438605ee2SAndrew Geissler { 12538605ee2SAndrew Geissler log<level::INFO>("org.freedesktop.systemd1 not on dbus yet"); 12638605ee2SAndrew Geissler } 12738605ee2SAndrew Geissler else 12838605ee2SAndrew Geissler { 129234a3179SAndrew Geissler log<level::ERR>("Failed to subscribe to systemd signals", 130234a3179SAndrew Geissler entry("SDBUSERR=%s", e.what())); 131234a3179SAndrew Geissler elog<InternalFailure>(); 132234a3179SAndrew Geissler } 13338605ee2SAndrew Geissler return; 13438605ee2SAndrew Geissler } 13538605ee2SAndrew Geissler 13638605ee2SAndrew Geissler // Call destructor on match callback since application is now subscribed to 13738605ee2SAndrew Geissler // systemd signals 13838605ee2SAndrew Geissler this->systemdNameOwnedChangedSignal.~match(); 139234a3179SAndrew Geissler 140234a3179SAndrew Geissler return; 141234a3179SAndrew Geissler } 142234a3179SAndrew Geissler 143234a3179SAndrew Geissler } // namespace manager 144234a3179SAndrew Geissler } // namespace state 145234a3179SAndrew Geissler } // namespace phosphor 146