1 #include "systemd_target_signal.hpp" 2 3 #include <phosphor-logging/elog-errors.hpp> 4 #include <phosphor-logging/lg2.hpp> 5 #include <sdbusplus/exception.hpp> 6 #include <sdbusplus/server/manager.hpp> 7 #include <sdeventplus/event.hpp> 8 #include <xyz/openbmc_project/Common/error.hpp> 9 10 namespace phosphor 11 { 12 namespace state 13 { 14 namespace manager 15 { 16 17 using phosphor::logging::elog; 18 PHOSPHOR_LOG2_USING; 19 20 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 21 22 void SystemdTargetLogging::logError(const std::string& errorLog, 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(errorLog); 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::exception& e) 38 { 39 error("Failed to create systemd target error, error:{ERROR_MSG}, " 40 "result:{RESULT}, exception:{ERROR}", 41 "ERROR_MSG", errorLog, "RESULT", result, "ERROR", e); 42 } 43 } 44 45 const std::string SystemdTargetLogging::processError(const std::string& unit, 46 const std::string& result) 47 { 48 auto targetEntry = this->targetData.find(unit); 49 if (targetEntry != this->targetData.end()) 50 { 51 // Check if its result matches any of our monitored errors 52 if (std::find(targetEntry->second.errorsToMonitor.begin(), 53 targetEntry->second.errorsToMonitor.end(), 54 result) != targetEntry->second.errorsToMonitor.end()) 55 { 56 info( 57 "Monitored systemd unit has hit an error, unit:{UNIT}, result:{RESULT}", 58 "UNIT", unit, "RESULT", result); 59 return (targetEntry->second.errorToLog); 60 } 61 } 62 63 // Check if it's in our list of services to monitor 64 if (std::find(this->serviceData.begin(), this->serviceData.end(), unit) != 65 this->serviceData.end()) 66 { 67 if (result == "failed") 68 { 69 info( 70 "Monitored systemd service has hit an error, unit:{UNIT}, result:{RESULT}", 71 "UNIT", unit, "RESULT", result); 72 return (std::string{ 73 "xyz.openbmc_project.State.Error.CriticalServiceFailure"}); 74 } 75 } 76 77 return (std::string{}); 78 } 79 80 void SystemdTargetLogging::systemdUnitChange(sdbusplus::message::message& msg) 81 { 82 uint32_t id; 83 sdbusplus::message::object_path objPath; 84 std::string unit{}; 85 std::string result{}; 86 87 msg.read(id, objPath, unit, result); 88 89 // In most cases it will just be success, in which case just return 90 if (result != "done") 91 { 92 const std::string error = processError(unit, result); 93 94 // If this is a monitored error then log it 95 if (!error.empty()) 96 { 97 logError(error, result); 98 } 99 } 100 return; 101 } 102 103 void SystemdTargetLogging::processNameChangeSignal( 104 sdbusplus::message::message& msg) 105 { 106 std::string name; // well-known 107 std::string old_owner; // unique-name 108 std::string new_owner; // unique-name 109 110 msg.read(name, old_owner, new_owner); 111 112 // Looking for systemd to be on dbus so we can call it 113 if (name == "org.freedesktop.systemd1") 114 { 115 info("org.freedesktop.systemd1 is now on dbus"); 116 subscribeToSystemdSignals(); 117 } 118 return; 119 } 120 121 void SystemdTargetLogging::subscribeToSystemdSignals() 122 { 123 auto method = this->bus.new_method_call( 124 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 125 "org.freedesktop.systemd1.Manager", "Subscribe"); 126 127 try 128 { 129 this->bus.call(method); 130 } 131 catch (const sdbusplus::exception::exception& e) 132 { 133 // If error indicates systemd is not on dbus yet then do nothing. 134 // The systemdNameChangeSignals callback will detect when it is on 135 // dbus and then call this function again 136 const std::string noDbus("org.freedesktop.DBus.Error.ServiceUnknown"); 137 if (noDbus == e.name()) 138 { 139 info("org.freedesktop.systemd1 not on dbus yet"); 140 } 141 else 142 { 143 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", 144 e); 145 elog<InternalFailure>(); 146 } 147 return; 148 } 149 150 // Call destructor on match callback since application is now subscribed to 151 // systemd signals 152 this->systemdNameOwnedChangedSignal.~match(); 153 154 return; 155 } 156 157 } // namespace manager 158 } // namespace state 159 } // namespace phosphor 160