blob: 7d1d1db83af069069ba4e68b8093aa4fd5bebc72 [file] [log] [blame]
Andrew Geisslere426b582020-05-28 12:40:55 -05001#include "systemd_target_signal.hpp"
2
Andrew Geissler234a3172019-08-09 14:30:02 -05003#include <phosphor-logging/elog-errors.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -05004#include <phosphor-logging/log.hpp>
5#include <sdbusplus/exception.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -05006#include <sdbusplus/server/manager.hpp>
7#include <sdeventplus/event.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -05008#include <xyz/openbmc_project/Common/error.hpp>
9
10namespace phosphor
11{
12namespace state
13{
14namespace manager
15{
16
17using phosphor::logging::elog;
18using phosphor::logging::entry;
19using phosphor::logging::level;
20using phosphor::logging::log;
21using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
22
23void SystemdTargetLogging::logError(const std::string& error,
24 const std::string& result)
25{
26 auto method = this->bus.new_method_call(
27 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
28 "xyz.openbmc_project.Logging.Create", "Create");
29 // Signature is ssa{ss}
30 method.append(error);
31 method.append("xyz.openbmc_project.Logging.Entry.Level.Critical");
32 method.append(std::array<std::pair<std::string, std::string>, 1>(
33 {std::pair<std::string, std::string>({"SYSTEMD_RESULT", result})}));
34 try
35 {
36 this->bus.call_noreply(method);
37 }
38 catch (const sdbusplus::exception::SdBusError& e)
39 {
40 log<level::ERR>("Failed to create systemd target error",
41 entry("ERROR=%s", error.c_str()),
42 entry("RESULT=%s", result.c_str()),
43 entry("SDBUSERR=%s", e.what()));
44 }
45}
46
47const std::string* SystemdTargetLogging::processError(const std::string& unit,
48 const std::string& result)
49{
50 auto targetEntry = this->targetData.find(unit);
51 if (targetEntry != this->targetData.end())
52 {
53 // Check if its result matches any of our monitored errors
54 if (std::find(targetEntry->second.errorsToMonitor.begin(),
55 targetEntry->second.errorsToMonitor.end(),
56 result) != targetEntry->second.errorsToMonitor.end())
57 {
58 log<level::INFO>("Monitored systemd unit has hit an error",
59 entry("UNIT=%s", unit.c_str()),
60 entry("RESULT=%s", result.c_str()));
61 return (&targetEntry->second.errorToLog);
62 }
63 }
Andrew Geisslerb154fa92019-12-10 15:18:10 -060064 return nullptr;
Andrew Geissler234a3172019-08-09 14:30:02 -050065}
66
67void SystemdTargetLogging::systemdUnitChange(sdbusplus::message::message& msg)
68{
69 uint32_t id;
70 sdbusplus::message::object_path objPath;
71 std::string unit{};
72 std::string result{};
73
74 msg.read(id, objPath, unit, result);
75
76 // In most cases it will just be success, in which case just return
77 if (result != "done")
78 {
79 const std::string* error = processError(unit, result);
80
81 // If this is a monitored error then log it
82 if (error)
83 {
84 logError(*error, result);
85 }
86 }
87 return;
88}
89
Andrew Geissler38605ee2019-11-11 16:01:56 -060090void SystemdTargetLogging::processNameChangeSignal(
91 sdbusplus::message::message& msg)
92{
93 std::string name; // well-known
94 std::string old_owner; // unique-name
95 std::string new_owner; // unique-name
96
97 msg.read(name, old_owner, new_owner);
98
99 // Looking for systemd to be on dbus so we can call it
100 if (name == "org.freedesktop.systemd1")
101 {
102 log<level::INFO>("org.freedesktop.systemd1 is now on dbus");
103 subscribeToSystemdSignals();
104 }
105 return;
106}
107
Andrew Geissler234a3172019-08-09 14:30:02 -0500108void SystemdTargetLogging::subscribeToSystemdSignals()
109{
110 auto method = this->bus.new_method_call(
111 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
112 "org.freedesktop.systemd1.Manager", "Subscribe");
113
114 try
115 {
116 this->bus.call(method);
117 }
118 catch (const sdbusplus::exception::SdBusError& e)
119 {
Andrew Geissler38605ee2019-11-11 16:01:56 -0600120 // If error indicates systemd is not on dbus yet then do nothing.
121 // The systemdNameChangeSignals callback will detect when it is on
122 // dbus and then call this function again
123 const std::string noDbus("org.freedesktop.DBus.Error.ServiceUnknown");
124 if (noDbus == e.name())
125 {
126 log<level::INFO>("org.freedesktop.systemd1 not on dbus yet");
127 }
128 else
129 {
130 log<level::ERR>("Failed to subscribe to systemd signals",
131 entry("SDBUSERR=%s", e.what()));
132 elog<InternalFailure>();
133 }
134 return;
Andrew Geissler234a3172019-08-09 14:30:02 -0500135 }
136
Andrew Geissler38605ee2019-11-11 16:01:56 -0600137 // Call destructor on match callback since application is now subscribed to
138 // systemd signals
139 this->systemdNameOwnedChangedSignal.~match();
140
Andrew Geissler234a3172019-08-09 14:30:02 -0500141 return;
142}
143
144} // namespace manager
145} // namespace state
146} // namespace phosphor