1 #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>
6 #include <systemd_target_signal.hpp>
7 #include <xyz/openbmc_project/Common/error.hpp>
8 
9 namespace phosphor
10 {
11 namespace state
12 {
13 namespace manager
14 {
15 
16 using phosphor::logging::elog;
17 using phosphor::logging::entry;
18 using phosphor::logging::level;
19 using phosphor::logging::log;
20 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
21 
22 void 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 
46 const 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     }
63     return {nullptr};
64 }
65 
66 void 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 
89 void SystemdTargetLogging::subscribeToSystemdSignals()
90 {
91     auto method = this->bus.new_method_call(
92         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
93         "org.freedesktop.systemd1.Manager", "Subscribe");
94 
95     try
96     {
97         this->bus.call(method);
98     }
99     catch (const sdbusplus::exception::SdBusError& e)
100     {
101         log<level::ERR>("Failed to subscribe to systemd signals",
102                         entry("SDBUSERR=%s", e.what()));
103         elog<InternalFailure>();
104     }
105 
106     return;
107 }
108 
109 } // namespace manager
110 } // namespace state
111 } // namespace phosphor
112