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