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>
6769a62f1SAndrew 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     }
63*b154fa9cSAndrew 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