blob: 462a84e3d30e2f66503b0b7c0ad6617becb32c45 [file] [log] [blame]
George Liu616a0712021-02-18 10:50:24 +08001#include "utils.hpp"
George Liudef5f5a2020-04-10 11:23:52 +08002
George Liudef5f5a2020-04-10 11:23:52 +08003#include <phosphor-logging/log.hpp>
George Liu616a0712021-02-18 10:50:24 +08004#include <sdbusplus/exception.hpp>
5#include <sdeventplus/event.hpp>
George Liudef5f5a2020-04-10 11:23:52 +08006
7#include <filesystem>
8#include <fstream>
George Liudef5f5a2020-04-10 11:23:52 +08009
10namespace fs = std::filesystem;
11
George Liu616a0712021-02-18 10:50:24 +080012using namespace phosphor::logging;
George Liudef5f5a2020-04-10 11:23:52 +080013
George Liu616a0712021-02-18 10:50:24 +080014namespace phosphor
George Liudef5f5a2020-04-10 11:23:52 +080015{
George Liu616a0712021-02-18 10:50:24 +080016namespace led
17{
George Liudef5f5a2020-04-10 11:23:52 +080018
George Liu616a0712021-02-18 10:50:24 +080019static constexpr auto confFileName = "led-group-config.json";
20static constexpr auto confOverridePath = "/etc/phosphor-led-manager";
21static constexpr auto confBasePath = "/usr/share/phosphor-led-manager";
22static constexpr auto confCompatibleInterface =
23 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
24static constexpr auto confCompatibleProperty = "Names";
25
26class JsonConfig
27{
28 public:
29 /**
30 * @brief Constructor
31 *
32 * Looks for the JSON config file. If it can't find one, then it
33 * will watch entity-manager for the IBMCompatibleSystem interface
34 * to show up.
35 *
36 * @param[in] bus - The D-Bus object
37 * @param[in] event - sd event handler
38 */
39 JsonConfig(sdbusplus::bus::bus& bus, sdeventplus::Event& event) :
40 event(event)
George Liudef5f5a2020-04-10 11:23:52 +080041 {
George Liu616a0712021-02-18 10:50:24 +080042 match = std::make_unique<sdbusplus::server::match::match>(
43 bus,
44 sdbusplus::bus::match::rules::interfacesAdded() +
45 sdbusplus::bus::match::rules::sender(
46 "xyz.openbmc_project.EntityManager"),
47 std::bind(&JsonConfig::ifacesAddedCallback, this,
48 std::placeholders::_1));
49 getFilePath();
50
51 if (!confFile.empty())
52 {
53 match.reset();
54 }
George Liudef5f5a2020-04-10 11:23:52 +080055 }
56
George Liu616a0712021-02-18 10:50:24 +080057 /**
58 * @brief Get the configuration file
59 *
60 * @return filesystem path
61 */
62 inline const fs::path& getConfFile() const
George Liudef5f5a2020-04-10 11:23:52 +080063 {
George Liu616a0712021-02-18 10:50:24 +080064 return confFile;
George Liudef5f5a2020-04-10 11:23:52 +080065 }
George Liu616a0712021-02-18 10:50:24 +080066
67 private:
68 /** @brief Check the file path exists
69 *
70 * @param[in] names - Vector of the confCompatible Property
71 *
72 * @return - True or False
73 */
74 bool filePathExists(const std::vector<std::string>& names)
George Liudef5f5a2020-04-10 11:23:52 +080075 {
George Liu616a0712021-02-18 10:50:24 +080076 auto it =
77 std::find_if(names.begin(), names.end(), [this](const auto& name) {
78 auto tempConfFile =
79 fs::path{confBasePath} / name / confFileName;
80 if (fs::exists(tempConfFile))
81 {
82 confFile = tempConfFile;
83 return true;
84 }
85 return false;
86 });
87 return it == names.end() ? false : true;
88 }
89
90 /**
91 * @brief The interfacesAdded callback function that looks for
92 * the IBMCompatibleSystem interface. If it finds it,
93 * it uses the Names property in the interface to find
94 * the JSON config file to use.
95 *
96 * @param[in] msg - The D-Bus message contents
97 */
98 void ifacesAddedCallback(sdbusplus::message::message& msg)
99 {
100 sdbusplus::message::object_path path;
101 std::map<std::string,
102 std::map<std::string, std::variant<std::vector<std::string>>>>
103 interfaces;
104
105 msg.read(path, interfaces);
106
107 if (interfaces.find(confCompatibleInterface) == interfaces.end())
108 {
109 return;
110 }
111
112 // Get the "Name" property value of the
113 // "xyz.openbmc_project.Configuration.IBMCompatibleSystem" interface
114 const auto& properties = interfaces.at(confCompatibleInterface);
115
116 if (properties.find(confCompatibleProperty) == properties.end())
117 {
118 return;
119 }
120 auto names = std::get<std::vector<std::string>>(
121 properties.at(confCompatibleProperty));
122
123 if (filePathExists(names))
124 {
125 match.reset();
126
127 // This results in event.loop() exiting in getSystemLedMap
128 event.exit(0);
129 }
130 }
131
132 /**
133 * Get the json configuration file. The first location found to contain the
134 * json config file from the following locations in order.
135 * confOverridePath: /etc/phosphor-led-manager/led-group-config.json
136 * confBasePath: /usr/shard/phosphor-led-manager/led-group-config.json
137 * the name property of the confCompatibleInterface:
138 * /usr/shard/phosphor-led-manager/${Name}/led-group-config.json
139 *
140 * @brief Get the configuration file to be used
141 *
142 * @return
143 */
144 const void getFilePath()
145 {
146 // Check override location
147 confFile = fs::path{confOverridePath} / confFileName;
148 if (fs::exists(confFile))
149 {
150 return;
151 }
152
153 // If the default file is there, use it
154 confFile = fs::path{confBasePath} / confFileName;
155 if (fs::exists(confFile))
156 {
157 return;
158 }
159 confFile.clear();
160
161 try
162 {
163 // Get all objects implementing the compatible interface
164 auto objects =
165 dBusHandler.getSubTreePaths("/", confCompatibleInterface);
166 for (const auto& path : objects)
167 {
168 try
169 {
170 // Retrieve json config compatible relative path locations
171 auto value = dBusHandler.getProperty(
172 path, confCompatibleInterface, confCompatibleProperty);
173
174 auto confCompatValues =
175 std::get<std::vector<std::string>>(value);
176
177 // Look for a config file at each name relative to the base
178 // path and use the first one found
179 if (filePathExists(confCompatValues))
180 {
181 // Use the first config file found at a listed location
182 break;
183 }
184 confFile.clear();
185 }
186 catch (const sdbusplus::exception::SdBusError& e)
187 {
188 // Property unavailable on object.
189 log<level::ERR>(
190 "Failed to get Names property",
George Liudef5f5a2020-04-10 11:23:52 +0800191 entry("ERROR=%s", e.what()),
George Liu616a0712021-02-18 10:50:24 +0800192 entry("INTERFACE=%s", confCompatibleInterface),
193 entry("PATH=%s", path.c_str()));
George Liudef5f5a2020-04-10 11:23:52 +0800194
George Liu616a0712021-02-18 10:50:24 +0800195 confFile.clear();
196 }
197 }
198 }
199 catch (const sdbusplus::exception::SdBusError& e)
200 {
201 log<level::ERR>("Failed to call the SubTreePaths method",
202 entry("ERROR=%s", e.what()),
203 entry("INTERFACE=%s", confCompatibleInterface));
204 }
George Liu17fcb4d2020-06-30 18:12:53 +0800205 return;
206 }
207
George Liu616a0712021-02-18 10:50:24 +0800208 private:
209 /**
210 * @brief sd event handler.
211 */
212 sdeventplus::Event& event;
George Liu17fcb4d2020-06-30 18:12:53 +0800213
George Liu616a0712021-02-18 10:50:24 +0800214 /**
215 * @brief The JSON config file
216 */
217 fs::path confFile;
George Liu17fcb4d2020-06-30 18:12:53 +0800218
George Liu616a0712021-02-18 10:50:24 +0800219 /**
220 * @brief The interfacesAdded match that is used to wait
221 * for the IBMCompatibleSystem interface to show up.
222 */
223 std::unique_ptr<sdbusplus::server::match::match> match;
George Liudef5f5a2020-04-10 11:23:52 +0800224
George Liu616a0712021-02-18 10:50:24 +0800225 /** DBusHandler class handles the D-Bus operations */
226 utils::DBusHandler dBusHandler;
227};
228} // namespace led
229} // namespace phosphor