1e426b589SAndrew Geissler #include "systemd_target_signal.hpp" 2e426b589SAndrew Geissler 3234a3179SAndrew Geissler #include <phosphor-logging/elog-errors.hpp> 48ffdb269SAndrew Geissler #include <phosphor-logging/lg2.hpp> 5e426b589SAndrew Geissler #include <sdbusplus/exception.hpp> 6234a3179SAndrew Geissler #include <sdbusplus/server/manager.hpp> 7234a3179SAndrew Geissler #include <sdeventplus/event.hpp> 8234a3179SAndrew Geissler #include <xyz/openbmc_project/Common/error.hpp> 9234a3179SAndrew Geissler 10234a3179SAndrew Geissler namespace phosphor 11234a3179SAndrew Geissler { 12234a3179SAndrew Geissler namespace state 13234a3179SAndrew Geissler { 14234a3179SAndrew Geissler namespace manager 15234a3179SAndrew Geissler { 16234a3179SAndrew Geissler 17234a3179SAndrew Geissler using phosphor::logging::elog; 188ffdb269SAndrew Geissler PHOSPHOR_LOG2_USING; 198ffdb269SAndrew Geissler 20234a3179SAndrew Geissler using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 21234a3179SAndrew Geissler 22*21d305e2SAndrew Geissler void SystemdTargetLogging::createBmcDump() 23*21d305e2SAndrew Geissler { 24*21d305e2SAndrew Geissler auto method = this->bus.new_method_call( 25*21d305e2SAndrew Geissler "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump/bmc", 26*21d305e2SAndrew Geissler "xyz.openbmc_project.Dump.Create", "CreateDump"); 27*21d305e2SAndrew Geissler method.append( 28*21d305e2SAndrew Geissler std::vector< 29*21d305e2SAndrew Geissler std::pair<std::string, std::variant<std::string, uint64_t>>>()); 30*21d305e2SAndrew Geissler try 31*21d305e2SAndrew Geissler { 32*21d305e2SAndrew Geissler this->bus.call_noreply(method); 33*21d305e2SAndrew Geissler } 34*21d305e2SAndrew Geissler catch (const sdbusplus::exception::exception& e) 35*21d305e2SAndrew Geissler { 36*21d305e2SAndrew Geissler error("Failed to create BMC dump, exception:{ERROR}", "ERROR", e); 37*21d305e2SAndrew Geissler // just continue, this is error path anyway so we're just collecting 38*21d305e2SAndrew Geissler // what we can 39*21d305e2SAndrew Geissler } 40*21d305e2SAndrew Geissler } 41*21d305e2SAndrew Geissler 428ffdb269SAndrew Geissler void SystemdTargetLogging::logError(const std::string& errorLog, 43e6841034SAndrew Geissler const std::string& result, 44e6841034SAndrew Geissler const std::string& unit) 45234a3179SAndrew Geissler { 46234a3179SAndrew Geissler auto method = this->bus.new_method_call( 47234a3179SAndrew Geissler "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 48234a3179SAndrew Geissler "xyz.openbmc_project.Logging.Create", "Create"); 49234a3179SAndrew Geissler // Signature is ssa{ss} 508ffdb269SAndrew Geissler method.append(errorLog); 51234a3179SAndrew Geissler method.append("xyz.openbmc_project.Logging.Entry.Level.Critical"); 52e6841034SAndrew Geissler method.append(std::array<std::pair<std::string, std::string>, 2>( 53e6841034SAndrew Geissler {std::pair<std::string, std::string>({"SYSTEMD_RESULT", result}), 54e6841034SAndrew Geissler std::pair<std::string, std::string>({"SYSTEMD_UNIT", unit})})); 55234a3179SAndrew Geissler try 56234a3179SAndrew Geissler { 57234a3179SAndrew Geissler this->bus.call_noreply(method); 58234a3179SAndrew Geissler } 590a675215SPatrick Williams catch (const sdbusplus::exception::exception& e) 60234a3179SAndrew Geissler { 618ffdb269SAndrew Geissler error("Failed to create systemd target error, error:{ERROR_MSG}, " 628ffdb269SAndrew Geissler "result:{RESULT}, exception:{ERROR}", 638ffdb269SAndrew Geissler "ERROR_MSG", errorLog, "RESULT", result, "ERROR", e); 64234a3179SAndrew Geissler } 65234a3179SAndrew Geissler } 66234a3179SAndrew Geissler 67f3870c62SAndrew Geissler const std::string SystemdTargetLogging::processError(const std::string& unit, 68234a3179SAndrew Geissler const std::string& result) 69234a3179SAndrew Geissler { 70234a3179SAndrew Geissler auto targetEntry = this->targetData.find(unit); 71234a3179SAndrew Geissler if (targetEntry != this->targetData.end()) 72234a3179SAndrew Geissler { 73234a3179SAndrew Geissler // Check if its result matches any of our monitored errors 74234a3179SAndrew Geissler if (std::find(targetEntry->second.errorsToMonitor.begin(), 75234a3179SAndrew Geissler targetEntry->second.errorsToMonitor.end(), 76234a3179SAndrew Geissler result) != targetEntry->second.errorsToMonitor.end()) 77234a3179SAndrew Geissler { 78ad65b2d6SAndrew Geissler info( 79ad65b2d6SAndrew Geissler "Monitored systemd unit has hit an error, unit:{UNIT}, result:{RESULT}", 808ffdb269SAndrew Geissler "UNIT", unit, "RESULT", result); 81f3870c62SAndrew Geissler return (targetEntry->second.errorToLog); 82234a3179SAndrew Geissler } 83234a3179SAndrew Geissler } 84f3870c62SAndrew Geissler 85f3870c62SAndrew Geissler // Check if it's in our list of services to monitor 86f3870c62SAndrew Geissler if (std::find(this->serviceData.begin(), this->serviceData.end(), unit) != 87f3870c62SAndrew Geissler this->serviceData.end()) 88f3870c62SAndrew Geissler { 89f3870c62SAndrew Geissler if (result == "failed") 90f3870c62SAndrew Geissler { 91f3870c62SAndrew Geissler info( 92f3870c62SAndrew Geissler "Monitored systemd service has hit an error, unit:{UNIT}, result:{RESULT}", 93f3870c62SAndrew Geissler "UNIT", unit, "RESULT", result); 94*21d305e2SAndrew Geissler 95*21d305e2SAndrew Geissler // Generate a BMC dump when a critical service fails 96*21d305e2SAndrew Geissler createBmcDump(); 97f3870c62SAndrew Geissler return (std::string{ 98f3870c62SAndrew Geissler "xyz.openbmc_project.State.Error.CriticalServiceFailure"}); 99f3870c62SAndrew Geissler } 100f3870c62SAndrew Geissler } 101f3870c62SAndrew Geissler 102f3870c62SAndrew Geissler return (std::string{}); 103234a3179SAndrew Geissler } 104234a3179SAndrew Geissler 105234a3179SAndrew Geissler void SystemdTargetLogging::systemdUnitChange(sdbusplus::message::message& msg) 106234a3179SAndrew Geissler { 107234a3179SAndrew Geissler uint32_t id; 108234a3179SAndrew Geissler sdbusplus::message::object_path objPath; 109234a3179SAndrew Geissler std::string unit{}; 110234a3179SAndrew Geissler std::string result{}; 111234a3179SAndrew Geissler 112234a3179SAndrew Geissler msg.read(id, objPath, unit, result); 113234a3179SAndrew Geissler 114234a3179SAndrew Geissler // In most cases it will just be success, in which case just return 115234a3179SAndrew Geissler if (result != "done") 116234a3179SAndrew Geissler { 117f3870c62SAndrew Geissler const std::string error = processError(unit, result); 118234a3179SAndrew Geissler 119234a3179SAndrew Geissler // If this is a monitored error then log it 120f3870c62SAndrew Geissler if (!error.empty()) 121234a3179SAndrew Geissler { 122e6841034SAndrew Geissler logError(error, result, unit); 123234a3179SAndrew Geissler } 124234a3179SAndrew Geissler } 125234a3179SAndrew Geissler return; 126234a3179SAndrew Geissler } 127234a3179SAndrew Geissler 12838605ee2SAndrew Geissler void SystemdTargetLogging::processNameChangeSignal( 12938605ee2SAndrew Geissler sdbusplus::message::message& msg) 13038605ee2SAndrew Geissler { 13138605ee2SAndrew Geissler std::string name; // well-known 13238605ee2SAndrew Geissler std::string old_owner; // unique-name 13338605ee2SAndrew Geissler std::string new_owner; // unique-name 13438605ee2SAndrew Geissler 13538605ee2SAndrew Geissler msg.read(name, old_owner, new_owner); 13638605ee2SAndrew Geissler 13738605ee2SAndrew Geissler // Looking for systemd to be on dbus so we can call it 13838605ee2SAndrew Geissler if (name == "org.freedesktop.systemd1") 13938605ee2SAndrew Geissler { 1408ffdb269SAndrew Geissler info("org.freedesktop.systemd1 is now on dbus"); 14138605ee2SAndrew Geissler subscribeToSystemdSignals(); 14238605ee2SAndrew Geissler } 14338605ee2SAndrew Geissler return; 14438605ee2SAndrew Geissler } 14538605ee2SAndrew Geissler 146234a3179SAndrew Geissler void SystemdTargetLogging::subscribeToSystemdSignals() 147234a3179SAndrew Geissler { 148234a3179SAndrew Geissler auto method = this->bus.new_method_call( 149234a3179SAndrew Geissler "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 150234a3179SAndrew Geissler "org.freedesktop.systemd1.Manager", "Subscribe"); 151234a3179SAndrew Geissler 152234a3179SAndrew Geissler try 153234a3179SAndrew Geissler { 154234a3179SAndrew Geissler this->bus.call(method); 155234a3179SAndrew Geissler } 1560a675215SPatrick Williams catch (const sdbusplus::exception::exception& e) 157234a3179SAndrew Geissler { 15838605ee2SAndrew Geissler // If error indicates systemd is not on dbus yet then do nothing. 15938605ee2SAndrew Geissler // The systemdNameChangeSignals callback will detect when it is on 16038605ee2SAndrew Geissler // dbus and then call this function again 16138605ee2SAndrew Geissler const std::string noDbus("org.freedesktop.DBus.Error.ServiceUnknown"); 16238605ee2SAndrew Geissler if (noDbus == e.name()) 16338605ee2SAndrew Geissler { 1648ffdb269SAndrew Geissler info("org.freedesktop.systemd1 not on dbus yet"); 16538605ee2SAndrew Geissler } 16638605ee2SAndrew Geissler else 16738605ee2SAndrew Geissler { 1688ffdb269SAndrew Geissler error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", 1698ffdb269SAndrew Geissler e); 170234a3179SAndrew Geissler elog<InternalFailure>(); 171234a3179SAndrew Geissler } 17238605ee2SAndrew Geissler return; 17338605ee2SAndrew Geissler } 17438605ee2SAndrew Geissler 17538605ee2SAndrew Geissler // Call destructor on match callback since application is now subscribed to 17638605ee2SAndrew Geissler // systemd signals 17738605ee2SAndrew Geissler this->systemdNameOwnedChangedSignal.~match(); 178234a3179SAndrew Geissler 179234a3179SAndrew Geissler return; 180234a3179SAndrew Geissler } 181234a3179SAndrew Geissler 182234a3179SAndrew Geissler } // namespace manager 183234a3179SAndrew Geissler } // namespace state 184234a3179SAndrew Geissler } // namespace phosphor 185