1953315d2SPatrick Williams #include "utils.hpp"
2953315d2SPatrick Williams
3953315d2SPatrick Williams #include <phosphor-logging/lg2.hpp>
4953315d2SPatrick Williams #include <sdbusplus/exception.hpp>
5953315d2SPatrick Williams #include <sdeventplus/event.hpp>
6953315d2SPatrick Williams
7953315d2SPatrick Williams #include <filesystem>
8953315d2SPatrick Williams #include <fstream>
9953315d2SPatrick Williams
10953315d2SPatrick Williams namespace fs = std::filesystem;
11953315d2SPatrick Williams
12953315d2SPatrick Williams namespace phosphor
13953315d2SPatrick Williams {
14953315d2SPatrick Williams namespace led
15953315d2SPatrick Williams {
16953315d2SPatrick Williams
17953315d2SPatrick Williams static constexpr auto confFileName = "led-group-config.json";
18953315d2SPatrick Williams static constexpr auto confOverridePath = "/etc/phosphor-led-manager";
19953315d2SPatrick Williams static constexpr auto confBasePath = "/usr/share/phosphor-led-manager";
20953315d2SPatrick Williams static constexpr auto confCompatibleInterface =
217d887627SPriyanga Ramasamy "xyz.openbmc_project.Inventory.Decorator.Compatible";
22953315d2SPatrick Williams static constexpr auto confCompatibleProperty = "Names";
23953315d2SPatrick Williams
24953315d2SPatrick Williams class JsonConfig
25953315d2SPatrick Williams {
26953315d2SPatrick Williams public:
27953315d2SPatrick Williams /**
28953315d2SPatrick Williams * @brief Constructor
29953315d2SPatrick Williams *
30953315d2SPatrick Williams * Looks for the JSON config file. If it can't find one, then it
317d887627SPriyanga Ramasamy * will watch entity-manager for the
327d887627SPriyanga Ramasamy * xyz.openbmc_project.Inventory.Decorator.Compatible interface to show up.
33953315d2SPatrick Williams *
34953315d2SPatrick Williams * @param[in] bus - The D-Bus object
35953315d2SPatrick Williams * @param[in] event - sd event handler
36953315d2SPatrick Williams */
JsonConfig(sdbusplus::bus_t & bus,sdeventplus::Event & event)373e073ba6SPatrick Williams JsonConfig(sdbusplus::bus_t& bus, sdeventplus::Event& event) : event(event)
38953315d2SPatrick Williams {
39953315d2SPatrick Williams match = std::make_unique<sdbusplus::bus::match_t>(
40953315d2SPatrick Williams bus,
41953315d2SPatrick Williams sdbusplus::bus::match::rules::interfacesAdded() +
42953315d2SPatrick Williams sdbusplus::bus::match::rules::sender(
43953315d2SPatrick Williams "xyz.openbmc_project.EntityManager"),
44226059b8SGeorge Liu [this](sdbusplus::message_t& m) { ifacesAddedCallback(m); });
45953315d2SPatrick Williams getFilePath();
46953315d2SPatrick Williams
47953315d2SPatrick Williams if (!confFile.empty())
48953315d2SPatrick Williams {
49953315d2SPatrick Williams match.reset();
50953315d2SPatrick Williams }
51953315d2SPatrick Williams }
52953315d2SPatrick Williams
53953315d2SPatrick Williams /**
54953315d2SPatrick Williams * @brief Get the configuration file
55953315d2SPatrick Williams *
56953315d2SPatrick Williams * @return filesystem path
57953315d2SPatrick Williams */
getConfFile() const58953315d2SPatrick Williams inline const fs::path& getConfFile() const
59953315d2SPatrick Williams {
60953315d2SPatrick Williams return confFile;
61953315d2SPatrick Williams }
62953315d2SPatrick Williams
63953315d2SPatrick Williams private:
64953315d2SPatrick Williams /** @brief Check the file path exists
65953315d2SPatrick Williams *
66953315d2SPatrick Williams * @param[in] names - Vector of the confCompatible Property
67953315d2SPatrick Williams *
68953315d2SPatrick Williams * @return - True or False
69953315d2SPatrick Williams */
filePathExists(const std::vector<std::string> & names)70953315d2SPatrick Williams bool filePathExists(const std::vector<std::string>& names)
71953315d2SPatrick Williams {
72543ac9f1SPatrick Williams auto it =
73543ac9f1SPatrick Williams std::find_if(names.begin(), names.end(), [this](const auto& name) {
747d887627SPriyanga Ramasamy auto configFileName = name + ".json";
757d887627SPriyanga Ramasamy auto configFilePath = fs::path{confBasePath} / configFileName;
767d887627SPriyanga Ramasamy if (fs::exists(configFilePath))
77953315d2SPatrick Williams {
787d887627SPriyanga Ramasamy confFile = configFilePath;
79953315d2SPatrick Williams return true;
80953315d2SPatrick Williams }
81953315d2SPatrick Williams return false;
82953315d2SPatrick Williams });
83*349d22e3SGeorge Liu return it != names.end();
84953315d2SPatrick Williams }
85953315d2SPatrick Williams
86953315d2SPatrick Williams /**
87953315d2SPatrick Williams * @brief The interfacesAdded callback function that looks for
887d887627SPriyanga Ramasamy * the xyz.openbmc_project.Inventory.Decorator.Compatible interface.
897d887627SPriyanga Ramasamy * If it finds it, it uses the Names property in the interface to find the
907d887627SPriyanga Ramasamy * JSON config file to use.
91953315d2SPatrick Williams *
92953315d2SPatrick Williams * @param[in] msg - The D-Bus message contents
93953315d2SPatrick Williams */
ifacesAddedCallback(sdbusplus::message_t & msg)943e073ba6SPatrick Williams void ifacesAddedCallback(sdbusplus::message_t& msg)
95953315d2SPatrick Williams {
96953315d2SPatrick Williams sdbusplus::message::object_path path;
97f2044037SPatrick Williams std::unordered_map<
98f2044037SPatrick Williams std::string,
99f2044037SPatrick Williams std::unordered_map<std::string,
100f2044037SPatrick Williams std::variant<std::vector<std::string>>>>
101953315d2SPatrick Williams interfaces;
102953315d2SPatrick Williams
103953315d2SPatrick Williams msg.read(path, interfaces);
104953315d2SPatrick Williams
105953315d2SPatrick Williams if (!interfaces.contains(confCompatibleInterface))
106953315d2SPatrick Williams {
107953315d2SPatrick Williams return;
108953315d2SPatrick Williams }
109953315d2SPatrick Williams
110953315d2SPatrick Williams // Get the "Name" property value of the
1117d887627SPriyanga Ramasamy // "xyz.openbmc_project.Inventory.Decorator.Compatible" interface
112953315d2SPatrick Williams const auto& properties = interfaces.at(confCompatibleInterface);
113953315d2SPatrick Williams
114953315d2SPatrick Williams if (!properties.contains(confCompatibleProperty))
115953315d2SPatrick Williams {
116953315d2SPatrick Williams return;
117953315d2SPatrick Williams }
118953315d2SPatrick Williams auto names = std::get<std::vector<std::string>>(
119953315d2SPatrick Williams properties.at(confCompatibleProperty));
120953315d2SPatrick Williams
121953315d2SPatrick Williams if (filePathExists(names))
122953315d2SPatrick Williams {
123953315d2SPatrick Williams match.reset();
124953315d2SPatrick Williams
125953315d2SPatrick Williams // This results in event.loop() exiting in getSystemLedMap
126953315d2SPatrick Williams event.exit(0);
127953315d2SPatrick Williams }
128953315d2SPatrick Williams }
129953315d2SPatrick Williams
130953315d2SPatrick Williams /**
131953315d2SPatrick Williams * Get the json configuration file. The first location found to contain the
132953315d2SPatrick Williams * json config file from the following locations in order.
133953315d2SPatrick Williams * confOverridePath: /etc/phosphor-led-manager/led-group-config.json
134953315d2SPatrick Williams * confBasePath: /usr/shard/phosphor-led-manager/led-group-config.json
135953315d2SPatrick Williams * the name property of the confCompatibleInterface:
136953315d2SPatrick Williams * /usr/shard/phosphor-led-manager/${Name}/led-group-config.json
137953315d2SPatrick Williams *
138953315d2SPatrick Williams * @brief Get the configuration file to be used
139953315d2SPatrick Williams *
140953315d2SPatrick Williams * @return
141953315d2SPatrick Williams */
getFilePath()142953315d2SPatrick Williams void getFilePath()
143953315d2SPatrick Williams {
144953315d2SPatrick Williams // Check override location
145953315d2SPatrick Williams confFile = fs::path{confOverridePath} / confFileName;
146953315d2SPatrick Williams if (fs::exists(confFile))
147953315d2SPatrick Williams {
148953315d2SPatrick Williams return;
149953315d2SPatrick Williams }
150953315d2SPatrick Williams
151953315d2SPatrick Williams // If the default file is there, use it
152953315d2SPatrick Williams confFile = fs::path{confBasePath} / confFileName;
153953315d2SPatrick Williams if (fs::exists(confFile))
154953315d2SPatrick Williams {
155953315d2SPatrick Williams return;
156953315d2SPatrick Williams }
157953315d2SPatrick Williams confFile.clear();
158953315d2SPatrick Williams
159953315d2SPatrick Williams try
160953315d2SPatrick Williams {
161953315d2SPatrick Williams // Get all objects implementing the compatible interface
16216181d1dSGeorge Liu auto objects = phosphor::led::utils::DBusHandler::getSubTreePaths(
16316181d1dSGeorge Liu "/", confCompatibleInterface);
164953315d2SPatrick Williams for (const auto& path : objects)
165953315d2SPatrick Williams {
166953315d2SPatrick Williams try
167953315d2SPatrick Williams {
168953315d2SPatrick Williams // Retrieve json config compatible relative path locations
16916181d1dSGeorge Liu auto value = phosphor::led::utils::DBusHandler::getProperty(
170953315d2SPatrick Williams path, confCompatibleInterface, confCompatibleProperty);
171953315d2SPatrick Williams
172953315d2SPatrick Williams auto confCompatValues =
173953315d2SPatrick Williams std::get<std::vector<std::string>>(value);
174953315d2SPatrick Williams
175953315d2SPatrick Williams // Look for a config file at each name relative to the base
176953315d2SPatrick Williams // path and use the first one found
177953315d2SPatrick Williams if (filePathExists(confCompatValues))
178953315d2SPatrick Williams {
179953315d2SPatrick Williams // Use the first config file found at a listed location
180953315d2SPatrick Williams break;
181953315d2SPatrick Williams }
182953315d2SPatrick Williams confFile.clear();
183953315d2SPatrick Williams }
1843e073ba6SPatrick Williams catch (const sdbusplus::exception_t& e)
185953315d2SPatrick Williams {
186953315d2SPatrick Williams // Property unavailable on object.
187953315d2SPatrick Williams lg2::error(
188953315d2SPatrick Williams "Failed to get Names property, ERROR = {ERROR}, INTERFACES = {INTERFACES}, PATH = {PATH}",
189953315d2SPatrick Williams "ERROR", e, "INTERFACE", confCompatibleInterface,
190953315d2SPatrick Williams "PATH", path);
191953315d2SPatrick Williams
192953315d2SPatrick Williams confFile.clear();
193953315d2SPatrick Williams }
194953315d2SPatrick Williams }
195953315d2SPatrick Williams }
1963e073ba6SPatrick Williams catch (const sdbusplus::exception_t& e)
197953315d2SPatrick Williams {
198953315d2SPatrick Williams lg2::error(
199953315d2SPatrick Williams "Failed to call the SubTreePaths method, ERROR = {ERROR}, INTERFACE = {INTERFACE}",
200953315d2SPatrick Williams "ERROR", e, "INTERFACE", confCompatibleInterface);
201953315d2SPatrick Williams }
202953315d2SPatrick Williams return;
203953315d2SPatrick Williams }
204953315d2SPatrick Williams
205953315d2SPatrick Williams /**
206953315d2SPatrick Williams * @brief sd event handler.
207953315d2SPatrick Williams */
208953315d2SPatrick Williams sdeventplus::Event& event;
209953315d2SPatrick Williams
210953315d2SPatrick Williams /**
211953315d2SPatrick Williams * @brief The JSON config file
212953315d2SPatrick Williams */
213953315d2SPatrick Williams fs::path confFile;
214953315d2SPatrick Williams
215953315d2SPatrick Williams /**
216953315d2SPatrick Williams * @brief The interfacesAdded match that is used to wait
2177d887627SPriyanga Ramasamy * for the xyz.openbmc_project.Inventory.Decorator.Compatible
2187d887627SPriyanga Ramasamy * interface to show up.
219953315d2SPatrick Williams */
220953315d2SPatrick Williams std::unique_ptr<sdbusplus::bus::match_t> match;
221953315d2SPatrick Williams };
2227217c035SPatrick Williams
2237217c035SPatrick Williams /** Blocking call to find the JSON Config from DBus. */
getJsonConfig()2247217c035SPatrick Williams auto getJsonConfig()
2257217c035SPatrick Williams {
2267217c035SPatrick Williams // Get a new Dbus
2277217c035SPatrick Williams auto bus = sdbusplus::bus::new_bus();
2287217c035SPatrick Williams
2297217c035SPatrick Williams // Get a new event loop
2307217c035SPatrick Williams auto event = sdeventplus::Event::get_new();
2317217c035SPatrick Williams
2327217c035SPatrick Williams // Attach the bus to sd_event to service user requests
2337217c035SPatrick Williams bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT);
2347217c035SPatrick Williams phosphor::led::JsonConfig jsonConfig(bus, event);
2357217c035SPatrick Williams
2367217c035SPatrick Williams // The event loop will be terminated from inside of a function in JsonConfig
2377217c035SPatrick Williams // after finding the configuration file
2387217c035SPatrick Williams if (jsonConfig.getConfFile().empty())
2397217c035SPatrick Williams {
2407217c035SPatrick Williams event.loop();
2417217c035SPatrick Williams }
2427217c035SPatrick Williams
2437217c035SPatrick Williams // Detach the bus from its sd_event event loop object
2447217c035SPatrick Williams bus.detach_event();
2457217c035SPatrick Williams
2467217c035SPatrick Williams return jsonConfig.getConfFile();
2477217c035SPatrick Williams }
2487217c035SPatrick Williams
249953315d2SPatrick Williams } // namespace led
250953315d2SPatrick Williams } // namespace phosphor
251