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