1*099543e4SBrad Bishop // SPDX-License-Identifier: Apache-2.0
2*099543e4SBrad Bishop 
3*099543e4SBrad Bishop /**@file functions.cpp*/
4*099543e4SBrad Bishop 
5*099543e4SBrad Bishop #include "functions.hpp"
6*099543e4SBrad Bishop 
7*099543e4SBrad Bishop #include <sdbusplus/bus.hpp>
8*099543e4SBrad Bishop #include <sdbusplus/bus/match.hpp>
9*099543e4SBrad Bishop #include <sdbusplus/message.hpp>
10*099543e4SBrad Bishop #include <sdeventplus/event.hpp>
11*099543e4SBrad Bishop 
12*099543e4SBrad Bishop #include <filesystem>
13*099543e4SBrad Bishop #include <functional>
14*099543e4SBrad Bishop #include <iostream>
15*099543e4SBrad Bishop #include <map>
16*099543e4SBrad Bishop #include <memory>
17*099543e4SBrad Bishop #include <string>
18*099543e4SBrad Bishop #include <variant>
19*099543e4SBrad Bishop #include <vector>
20*099543e4SBrad Bishop 
21*099543e4SBrad Bishop namespace functions
22*099543e4SBrad Bishop {
23*099543e4SBrad Bishop namespace process_hostfirmware
24*099543e4SBrad Bishop {
25*099543e4SBrad Bishop 
26*099543e4SBrad Bishop /**
27*099543e4SBrad Bishop  * @brief Issue callbacks safely
28*099543e4SBrad Bishop  *
29*099543e4SBrad Bishop  * std::function can be empty, so this wrapper method checks for that prior to
30*099543e4SBrad Bishop  * calling it to avoid std::bad_function_call
31*099543e4SBrad Bishop  *
32*099543e4SBrad Bishop  * @tparam Sig the types of the std::function arguments
33*099543e4SBrad Bishop  * @tparam Args the deduced argument types
34*099543e4SBrad Bishop  * @param[in] callback the callback being wrapped
35*099543e4SBrad Bishop  * @param[in] args the callback arguments
36*099543e4SBrad Bishop  */
37*099543e4SBrad Bishop template <typename... Sig, typename... Args>
38*099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args)
39*099543e4SBrad Bishop {
40*099543e4SBrad Bishop     if (callback)
41*099543e4SBrad Bishop     {
42*099543e4SBrad Bishop         callback(std::forward<Args>(args)...);
43*099543e4SBrad Bishop     }
44*099543e4SBrad Bishop }
45*099543e4SBrad Bishop 
46*099543e4SBrad Bishop /**
47*099543e4SBrad Bishop  * @brief Get file extensions for IBMCompatibleSystem
48*099543e4SBrad Bishop  *
49*099543e4SBrad Bishop  * IBM host firmware can be deployed as blobs (files) in a filesystem.  Host
50*099543e4SBrad Bishop  * firmware blobs for different values of
51*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with
52*099543e4SBrad Bishop  * different filename extensions.  getExtensionsForIbmCompatibleSystem
53*099543e4SBrad Bishop  * maintains the mapping from a given value of
54*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of
55*099543e4SBrad Bishop  * filename extensions.
56*099543e4SBrad Bishop  *
57*099543e4SBrad Bishop  * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and
58*099543e4SBrad Bishop  * the extensions parameter is reset with the map entry.  If no mapping is
59*099543e4SBrad Bishop  * found getExtensionsForIbmCompatibleSystem returns false and extensions is
60*099543e4SBrad Bishop  * unmodified.
61*099543e4SBrad Bishop  *
62*099543e4SBrad Bishop  * @param[in] extensionMap a map of
63*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
64*099543e4SBrad Bishop  * file extensions.
65*099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
66*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
67*099543e4SBrad Bishop  * @param[out] extentions the host firmware blob file extensions
68*099543e4SBrad Bishop  * @return true if an entry was found, otherwise false
69*099543e4SBrad Bishop  */
70*099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem(
71*099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
72*099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
73*099543e4SBrad Bishop     std::vector<std::string>& extensions)
74*099543e4SBrad Bishop {
75*099543e4SBrad Bishop     for (const auto& system : ibmCompatibleSystem)
76*099543e4SBrad Bishop     {
77*099543e4SBrad Bishop         auto extensionMapIterator = extensionMap.find(system);
78*099543e4SBrad Bishop         if (extensionMapIterator != extensionMap.end())
79*099543e4SBrad Bishop         {
80*099543e4SBrad Bishop             extensions = extensionMapIterator->second;
81*099543e4SBrad Bishop             return true;
82*099543e4SBrad Bishop         }
83*099543e4SBrad Bishop     }
84*099543e4SBrad Bishop 
85*099543e4SBrad Bishop     return false;
86*099543e4SBrad Bishop }
87*099543e4SBrad Bishop 
88*099543e4SBrad Bishop /**
89*099543e4SBrad Bishop  * @brief Write host firmware well-known name
90*099543e4SBrad Bishop  *
91*099543e4SBrad Bishop  * A wrapper around std::filesystem::create_symlink that avoids EEXIST by
92*099543e4SBrad Bishop  * deleting any pre-existing file.
93*099543e4SBrad Bishop  *
94*099543e4SBrad Bishop  * @param[in] linkTarget The link target argument to
95*099543e4SBrad Bishop  * std::filesystem::create_symlink
96*099543e4SBrad Bishop  * @param[in] linkPath The link path argument to std::filesystem::create_symlink
97*099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
98*099543e4SBrad Bishop  */
99*099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget,
100*099543e4SBrad Bishop                const std::filesystem::path& linkPath,
101*099543e4SBrad Bishop                const ErrorCallbackType& errorCallback)
102*099543e4SBrad Bishop {
103*099543e4SBrad Bishop     std::error_code ec;
104*099543e4SBrad Bishop 
105*099543e4SBrad Bishop     // remove files with the same name as the symlink to be created,
106*099543e4SBrad Bishop     // otherwise symlink will fail with EEXIST.
107*099543e4SBrad Bishop     if (!std::filesystem::remove(linkPath, ec))
108*099543e4SBrad Bishop     {
109*099543e4SBrad Bishop         if (ec)
110*099543e4SBrad Bishop         {
111*099543e4SBrad Bishop             makeCallback(errorCallback, linkPath, ec);
112*099543e4SBrad Bishop             return;
113*099543e4SBrad Bishop         }
114*099543e4SBrad Bishop     }
115*099543e4SBrad Bishop 
116*099543e4SBrad Bishop     std::filesystem::create_symlink(linkTarget, linkPath, ec);
117*099543e4SBrad Bishop     if (ec)
118*099543e4SBrad Bishop     {
119*099543e4SBrad Bishop         makeCallback(errorCallback, linkPath, ec);
120*099543e4SBrad Bishop         return;
121*099543e4SBrad Bishop     }
122*099543e4SBrad Bishop }
123*099543e4SBrad Bishop 
124*099543e4SBrad Bishop /**
125*099543e4SBrad Bishop  * @brief Find host firmware blob files that need well-known names
126*099543e4SBrad Bishop  *
127*099543e4SBrad Bishop  * The IBM host firmware runtime looks for data and/or additional code while
128*099543e4SBrad Bishop  * bootstraping in files with well-known names.  findLinks uses the provided
129*099543e4SBrad Bishop  * extensions argument to find host firmware blob files that require a
130*099543e4SBrad Bishop  * well-known name.  When a blob is found, issue the provided callback
131*099543e4SBrad Bishop  * (typically a function that will write a symlink).
132*099543e4SBrad Bishop  *
133*099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
134*099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
135*099543e4SBrad Bishop  * @param[in] extentions The extensions of the firmware blob files denote a
136*099543e4SBrad Bishop  * host firmware blob file requires a well-known name.
137*099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
138*099543e4SBrad Bishop  * @param[in] linkCallback A callback made when host firmware blob files
139*099543e4SBrad Bishop  * needing a well known name are found.
140*099543e4SBrad Bishop  */
141*099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory,
142*099543e4SBrad Bishop                const std::vector<std::string>& extensions,
143*099543e4SBrad Bishop                const ErrorCallbackType& errorCallback,
144*099543e4SBrad Bishop                const LinkCallbackType& linkCallback)
145*099543e4SBrad Bishop {
146*099543e4SBrad Bishop     std::error_code ec;
147*099543e4SBrad Bishop     std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory,
148*099543e4SBrad Bishop                                                           ec);
149*099543e4SBrad Bishop     if (ec)
150*099543e4SBrad Bishop     {
151*099543e4SBrad Bishop         makeCallback(errorCallback, hostFirmwareDirectory, ec);
152*099543e4SBrad Bishop         return;
153*099543e4SBrad Bishop     }
154*099543e4SBrad Bishop 
155*099543e4SBrad Bishop     for (; directoryIterator != std::filesystem::end(directoryIterator);
156*099543e4SBrad Bishop          directoryIterator.increment(ec))
157*099543e4SBrad Bishop     {
158*099543e4SBrad Bishop         const auto& file = directoryIterator->path();
159*099543e4SBrad Bishop         if (ec)
160*099543e4SBrad Bishop         {
161*099543e4SBrad Bishop             makeCallback(errorCallback, file, ec);
162*099543e4SBrad Bishop             // quit here if the increment call failed otherwise the loop may
163*099543e4SBrad Bishop             // never finish
164*099543e4SBrad Bishop             break;
165*099543e4SBrad Bishop         }
166*099543e4SBrad Bishop 
167*099543e4SBrad Bishop         if (std::find(extensions.begin(), extensions.end(), file.extension()) ==
168*099543e4SBrad Bishop             extensions.end())
169*099543e4SBrad Bishop         {
170*099543e4SBrad Bishop             // this file doesn't have an extension or doesn't match any of the
171*099543e4SBrad Bishop             // provided extensions.
172*099543e4SBrad Bishop             continue;
173*099543e4SBrad Bishop         }
174*099543e4SBrad Bishop 
175*099543e4SBrad Bishop         auto linkPath(file.parent_path().append(
176*099543e4SBrad Bishop             static_cast<const std::string&>(file.stem())));
177*099543e4SBrad Bishop 
178*099543e4SBrad Bishop         makeCallback(linkCallback, file.filename(), linkPath, errorCallback);
179*099543e4SBrad Bishop     }
180*099543e4SBrad Bishop }
181*099543e4SBrad Bishop 
182*099543e4SBrad Bishop /**
183*099543e4SBrad Bishop  * @brief Make callbacks on
184*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
185*099543e4SBrad Bishop  *
186*099543e4SBrad Bishop  * Look for an instance of
187*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
188*099543e4SBrad Bishop  * argument and if found, issue the provided callback.
189*099543e4SBrad Bishop  *
190*099543e4SBrad Bishop  * @param[in] interfacesAndProperties the interfaces in which to look for an
191*099543e4SBrad Bishop  * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem
192*099543e4SBrad Bishop  * @param[in] callback the user callback to make if
193*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
194*099543e4SBrad Bishop  * interfacesAndProperties
195*099543e4SBrad Bishop  * @return true if interfacesAndProperties contained an instance of
196*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
197*099543e4SBrad Bishop  */
198*099543e4SBrad Bishop bool maybeCall(const std::map<std::string,
199*099543e4SBrad Bishop                               std::map<std::string,
200*099543e4SBrad Bishop                                        std::variant<std::vector<std::string>>>>&
201*099543e4SBrad Bishop                    interfacesAndProperties,
202*099543e4SBrad Bishop                const MaybeCallCallbackType& callback)
203*099543e4SBrad Bishop {
204*099543e4SBrad Bishop     using namespace std::string_literals;
205*099543e4SBrad Bishop 
206*099543e4SBrad Bishop     static const auto interfaceName =
207*099543e4SBrad Bishop         "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s;
208*099543e4SBrad Bishop     auto interfaceIterator = interfacesAndProperties.find(interfaceName);
209*099543e4SBrad Bishop     if (interfaceIterator == interfacesAndProperties.cend())
210*099543e4SBrad Bishop     {
211*099543e4SBrad Bishop         // IBMCompatibleSystem interface not found, so instruct the caller to
212*099543e4SBrad Bishop         // keep waiting or try again later.
213*099543e4SBrad Bishop         return false;
214*099543e4SBrad Bishop     }
215*099543e4SBrad Bishop     auto propertyIterator = interfaceIterator->second.find("Names"s);
216*099543e4SBrad Bishop     if (propertyIterator == interfaceIterator->second.cend())
217*099543e4SBrad Bishop     {
218*099543e4SBrad Bishop         // The interface exists but the property doesn't.  This is a bug in the
219*099543e4SBrad Bishop         // IBMCompatibleSystem implementation.  The caller should not try
220*099543e4SBrad Bishop         // again.
221*099543e4SBrad Bishop         std::cerr << "Names property not implemented on " << interfaceName
222*099543e4SBrad Bishop                   << "\n";
223*099543e4SBrad Bishop         return true;
224*099543e4SBrad Bishop     }
225*099543e4SBrad Bishop 
226*099543e4SBrad Bishop     const auto& ibmCompatibleSystem =
227*099543e4SBrad Bishop         std::get<std::vector<std::string>>(propertyIterator->second);
228*099543e4SBrad Bishop     if (callback)
229*099543e4SBrad Bishop     {
230*099543e4SBrad Bishop         callback(ibmCompatibleSystem);
231*099543e4SBrad Bishop     }
232*099543e4SBrad Bishop 
233*099543e4SBrad Bishop     // IBMCompatibleSystem found and callback issued.
234*099543e4SBrad Bishop     return true;
235*099543e4SBrad Bishop }
236*099543e4SBrad Bishop 
237*099543e4SBrad Bishop /**
238*099543e4SBrad Bishop  * @brief Make callbacks on
239*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
240*099543e4SBrad Bishop  *
241*099543e4SBrad Bishop  * Look for an instance of
242*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
243*099543e4SBrad Bishop  * argument and if found, issue the provided callback.
244*099543e4SBrad Bishop  *
245*099543e4SBrad Bishop  * @param[in] message the DBus message in which to look for an instance of
246*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
247*099543e4SBrad Bishop  * @param[in] callback the user callback to make if
248*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
249*099543e4SBrad Bishop  * message
250*099543e4SBrad Bishop  * @return true if message contained an instance of
251*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
252*099543e4SBrad Bishop  */
253*099543e4SBrad Bishop bool maybeCallMessage(sdbusplus::message::message& message,
254*099543e4SBrad Bishop                       const MaybeCallCallbackType& callback)
255*099543e4SBrad Bishop {
256*099543e4SBrad Bishop     std::map<std::string,
257*099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
258*099543e4SBrad Bishop         interfacesAndProperties;
259*099543e4SBrad Bishop     sdbusplus::message::object_path _;
260*099543e4SBrad Bishop     message.read(_, interfacesAndProperties);
261*099543e4SBrad Bishop     return maybeCall(interfacesAndProperties, callback);
262*099543e4SBrad Bishop }
263*099543e4SBrad Bishop 
264*099543e4SBrad Bishop /**
265*099543e4SBrad Bishop  * @brief Determine system support for host firmware well-known names.
266*099543e4SBrad Bishop  *
267*099543e4SBrad Bishop  * Using the provided extensionMap and
268*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if
269*099543e4SBrad Bishop  * well-known names for host firmare blob files are necessary and if so, create
270*099543e4SBrad Bishop  * them.
271*099543e4SBrad Bishop  *
272*099543e4SBrad Bishop  * @param[in] extensionMap a map of
273*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
274*099543e4SBrad Bishop  * file extensions.
275*099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
276*099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
277*099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
278*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
279*099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
280*099543e4SBrad Bishop  */
281*099543e4SBrad Bishop void maybeMakeLinks(
282*099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
283*099543e4SBrad Bishop     const std::filesystem::path& hostFirmwareDirectory,
284*099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
285*099543e4SBrad Bishop     const ErrorCallbackType& errorCallback)
286*099543e4SBrad Bishop {
287*099543e4SBrad Bishop     std::vector<std::string> extensions;
288*099543e4SBrad Bishop     if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
289*099543e4SBrad Bishop                                             extensions))
290*099543e4SBrad Bishop     {
291*099543e4SBrad Bishop         findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink);
292*099543e4SBrad Bishop     }
293*099543e4SBrad Bishop }
294*099543e4SBrad Bishop 
295*099543e4SBrad Bishop /**
296*099543e4SBrad Bishop  * @brief process host firmware
297*099543e4SBrad Bishop  *
298*099543e4SBrad Bishop  * Allocate a callback context and register for DBus.ObjectManager Interfaces
299*099543e4SBrad Bishop  * added signals from entity manager.
300*099543e4SBrad Bishop  *
301*099543e4SBrad Bishop  * Check the current entity manager object tree for a
302*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity
303*099543e4SBrad Bishop  * manager will be dbus activated if it is not running).  If one is found,
304*099543e4SBrad Bishop  * determine if symlinks need to be created and create them.  Instruct the
305*099543e4SBrad Bishop  * program event loop to exit.
306*099543e4SBrad Bishop  *
307*099543e4SBrad Bishop  * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
308*099543e4SBrad Bishop  * found return the callback context to main, where the program will sleep
309*099543e4SBrad Bishop  * until the callback is invoked one or more times and instructs the program
310*099543e4SBrad Bishop  * event loop to exit when
311*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added.
312*099543e4SBrad Bishop  *
313*099543e4SBrad Bishop  * @param[in] bus a DBus client connection
314*099543e4SBrad Bishop  * @param[in] extensionMap a map of
315*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
316*099543e4SBrad Bishop  * file extensions.
317*099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which processHostFirmware
318*099543e4SBrad Bishop  * should look for blob files.
319*099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
320*099543e4SBrad Bishop  * @param[in] loop a program event loop
321*099543e4SBrad Bishop  * @return nullptr if an instance of
322*099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a
323*099543e4SBrad Bishop  * pointer to an sdbusplus match object.
324*099543e4SBrad Bishop  */
325*099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware(
326*099543e4SBrad Bishop     sdbusplus::bus::bus& bus,
327*099543e4SBrad Bishop     std::map<std::string, std::vector<std::string>> extensionMap,
328*099543e4SBrad Bishop     std::filesystem::path hostFirmwareDirectory,
329*099543e4SBrad Bishop     ErrorCallbackType errorCallback, sdeventplus::Event& loop)
330*099543e4SBrad Bishop {
331*099543e4SBrad Bishop     // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't
332*099543e4SBrad Bishop     // be transfered to the match callback because they are needed in the non
333*099543e4SBrad Bishop     // async part of this function below, so they need to be moved to the heap.
334*099543e4SBrad Bishop     auto pExtensionMap =
335*099543e4SBrad Bishop         std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
336*099543e4SBrad Bishop     auto pHostFirmwareDirectory =
337*099543e4SBrad Bishop         std::make_shared<decltype(hostFirmwareDirectory)>(
338*099543e4SBrad Bishop             std::move(hostFirmwareDirectory));
339*099543e4SBrad Bishop     auto pErrorCallback =
340*099543e4SBrad Bishop         std::make_shared<decltype(errorCallback)>(std::move(errorCallback));
341*099543e4SBrad Bishop 
342*099543e4SBrad Bishop     // register for a callback in case the IBMCompatibleSystem interface has
343*099543e4SBrad Bishop     // not yet been published by entity manager.
344*099543e4SBrad Bishop     auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>(
345*099543e4SBrad Bishop         bus,
346*099543e4SBrad Bishop         sdbusplus::bus::match::rules::interfacesAdded() +
347*099543e4SBrad Bishop             sdbusplus::bus::match::rules::sender(
348*099543e4SBrad Bishop                 "xyz.openbmc_project.EntityManager"),
349*099543e4SBrad Bishop         [pExtensionMap, pHostFirmwareDirectory, pErrorCallback,
350*099543e4SBrad Bishop          &loop](auto& message) {
351*099543e4SBrad Bishop             // bind the extension map, host firmware directory, and error
352*099543e4SBrad Bishop             // callback to the maybeMakeLinks function.
353*099543e4SBrad Bishop             auto maybeMakeLinksWithArgsBound =
354*099543e4SBrad Bishop                 std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
355*099543e4SBrad Bishop                           std::cref(*pHostFirmwareDirectory),
356*099543e4SBrad Bishop                           std::placeholders::_1, std::cref(*pErrorCallback));
357*099543e4SBrad Bishop 
358*099543e4SBrad Bishop             // if the InterfacesAdded message contains an an instance of
359*099543e4SBrad Bishop             // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to
360*099543e4SBrad Bishop             // see if links are necessary on this system and if so, create
361*099543e4SBrad Bishop             // them.
362*099543e4SBrad Bishop             if (maybeCallMessage(message, maybeMakeLinksWithArgsBound))
363*099543e4SBrad Bishop             {
364*099543e4SBrad Bishop                 // The IBMCompatibleSystem interface was found and the links
365*099543e4SBrad Bishop                 // were created if applicable.  Instruct the event loop /
366*099543e4SBrad Bishop                 // subcommand to exit.
367*099543e4SBrad Bishop                 loop.exit(0);
368*099543e4SBrad Bishop             }
369*099543e4SBrad Bishop         });
370*099543e4SBrad Bishop 
371*099543e4SBrad Bishop     // now that we'll get a callback in the event of an InterfacesAdded signal
372*099543e4SBrad Bishop     // (potentially containing
373*099543e4SBrad Bishop     // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity
374*099543e4SBrad Bishop     // manager if it isn't running and enumerate its objects
375*099543e4SBrad Bishop     auto getManagedObjects = bus.new_method_call(
376*099543e4SBrad Bishop         "xyz.openbmc_project.EntityManager", "/",
377*099543e4SBrad Bishop         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
378*099543e4SBrad Bishop     auto reply = bus.call(getManagedObjects);
379*099543e4SBrad Bishop     std::map<std::string,
380*099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
381*099543e4SBrad Bishop         interfacesAndProperties;
382*099543e4SBrad Bishop     std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
383*099543e4SBrad Bishop         objects;
384*099543e4SBrad Bishop     reply.read(objects);
385*099543e4SBrad Bishop 
386*099543e4SBrad Bishop     // bind the extension map, host firmware directory, and error callback to
387*099543e4SBrad Bishop     // the maybeMakeLinks function.
388*099543e4SBrad Bishop     auto maybeMakeLinksWithArgsBound =
389*099543e4SBrad Bishop         std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
390*099543e4SBrad Bishop                   std::cref(*pHostFirmwareDirectory), std::placeholders::_1,
391*099543e4SBrad Bishop                   std::cref(*pErrorCallback));
392*099543e4SBrad Bishop 
393*099543e4SBrad Bishop     for (const auto& pair : objects)
394*099543e4SBrad Bishop     {
395*099543e4SBrad Bishop         std::tie(std::ignore, interfacesAndProperties) = pair;
396*099543e4SBrad Bishop         // if interfacesAndProperties contains an an instance of
397*099543e4SBrad Bishop         // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see
398*099543e4SBrad Bishop         // if links are necessary on this system and if so, create them
399*099543e4SBrad Bishop         if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound))
400*099543e4SBrad Bishop         {
401*099543e4SBrad Bishop             // The IBMCompatibleSystem interface is already on the bus and the
402*099543e4SBrad Bishop             // links were created if applicable.  Instruct the event loop to
403*099543e4SBrad Bishop             // exit.
404*099543e4SBrad Bishop             loop.exit(0);
405*099543e4SBrad Bishop             // The match object isn't needed anymore, so destroy it on return.
406*099543e4SBrad Bishop             return nullptr;
407*099543e4SBrad Bishop         }
408*099543e4SBrad Bishop     }
409*099543e4SBrad Bishop 
410*099543e4SBrad Bishop     // The IBMCompatibleSystem interface has not yet been published.  Move
411*099543e4SBrad Bishop     // ownership of the match callback to the caller.
412*099543e4SBrad Bishop     return interfacesAddedMatch;
413*099543e4SBrad Bishop }
414*099543e4SBrad Bishop } // namespace process_hostfirmware
415*099543e4SBrad Bishop } // namespace functions
416