1099543e4SBrad Bishop // SPDX-License-Identifier: Apache-2.0
2099543e4SBrad Bishop 
3099543e4SBrad Bishop /**@file functions.cpp*/
4099543e4SBrad Bishop 
5099543e4SBrad Bishop #include "functions.hpp"
6099543e4SBrad Bishop 
7099543e4SBrad Bishop #include <sdbusplus/bus.hpp>
8099543e4SBrad Bishop #include <sdbusplus/bus/match.hpp>
9*c79fa915SAdriana Kobylak #include <sdbusplus/exception.hpp>
10099543e4SBrad Bishop #include <sdbusplus/message.hpp>
11099543e4SBrad Bishop #include <sdeventplus/event.hpp>
12099543e4SBrad Bishop 
13099543e4SBrad Bishop #include <filesystem>
14099543e4SBrad Bishop #include <functional>
15099543e4SBrad Bishop #include <iostream>
16099543e4SBrad Bishop #include <map>
17099543e4SBrad Bishop #include <memory>
18099543e4SBrad Bishop #include <string>
19099543e4SBrad Bishop #include <variant>
20099543e4SBrad Bishop #include <vector>
21099543e4SBrad Bishop 
22099543e4SBrad Bishop namespace functions
23099543e4SBrad Bishop {
24099543e4SBrad Bishop namespace process_hostfirmware
25099543e4SBrad Bishop {
26099543e4SBrad Bishop 
27099543e4SBrad Bishop /**
28099543e4SBrad Bishop  * @brief Issue callbacks safely
29099543e4SBrad Bishop  *
30099543e4SBrad Bishop  * std::function can be empty, so this wrapper method checks for that prior to
31099543e4SBrad Bishop  * calling it to avoid std::bad_function_call
32099543e4SBrad Bishop  *
33099543e4SBrad Bishop  * @tparam Sig the types of the std::function arguments
34099543e4SBrad Bishop  * @tparam Args the deduced argument types
35099543e4SBrad Bishop  * @param[in] callback the callback being wrapped
36099543e4SBrad Bishop  * @param[in] args the callback arguments
37099543e4SBrad Bishop  */
38099543e4SBrad Bishop template <typename... Sig, typename... Args>
39099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args)
40099543e4SBrad Bishop {
41099543e4SBrad Bishop     if (callback)
42099543e4SBrad Bishop     {
43099543e4SBrad Bishop         callback(std::forward<Args>(args)...);
44099543e4SBrad Bishop     }
45099543e4SBrad Bishop }
46099543e4SBrad Bishop 
47099543e4SBrad Bishop /**
48099543e4SBrad Bishop  * @brief Get file extensions for IBMCompatibleSystem
49099543e4SBrad Bishop  *
50099543e4SBrad Bishop  * IBM host firmware can be deployed as blobs (files) in a filesystem.  Host
51099543e4SBrad Bishop  * firmware blobs for different values of
52099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with
53099543e4SBrad Bishop  * different filename extensions.  getExtensionsForIbmCompatibleSystem
54099543e4SBrad Bishop  * maintains the mapping from a given value of
55099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of
56099543e4SBrad Bishop  * filename extensions.
57099543e4SBrad Bishop  *
58099543e4SBrad Bishop  * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and
59099543e4SBrad Bishop  * the extensions parameter is reset with the map entry.  If no mapping is
60099543e4SBrad Bishop  * found getExtensionsForIbmCompatibleSystem returns false and extensions is
61099543e4SBrad Bishop  * unmodified.
62099543e4SBrad Bishop  *
63099543e4SBrad Bishop  * @param[in] extensionMap a map of
64099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
65099543e4SBrad Bishop  * file extensions.
66099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
67099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
68099543e4SBrad Bishop  * @param[out] extentions the host firmware blob file extensions
69099543e4SBrad Bishop  * @return true if an entry was found, otherwise false
70099543e4SBrad Bishop  */
71099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem(
72099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
73099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
74099543e4SBrad Bishop     std::vector<std::string>& extensions)
75099543e4SBrad Bishop {
76099543e4SBrad Bishop     for (const auto& system : ibmCompatibleSystem)
77099543e4SBrad Bishop     {
78099543e4SBrad Bishop         auto extensionMapIterator = extensionMap.find(system);
79099543e4SBrad Bishop         if (extensionMapIterator != extensionMap.end())
80099543e4SBrad Bishop         {
81099543e4SBrad Bishop             extensions = extensionMapIterator->second;
82099543e4SBrad Bishop             return true;
83099543e4SBrad Bishop         }
84099543e4SBrad Bishop     }
85099543e4SBrad Bishop 
86099543e4SBrad Bishop     return false;
87099543e4SBrad Bishop }
88099543e4SBrad Bishop 
89099543e4SBrad Bishop /**
90099543e4SBrad Bishop  * @brief Write host firmware well-known name
91099543e4SBrad Bishop  *
92099543e4SBrad Bishop  * A wrapper around std::filesystem::create_symlink that avoids EEXIST by
93099543e4SBrad Bishop  * deleting any pre-existing file.
94099543e4SBrad Bishop  *
95099543e4SBrad Bishop  * @param[in] linkTarget The link target argument to
96099543e4SBrad Bishop  * std::filesystem::create_symlink
97099543e4SBrad Bishop  * @param[in] linkPath The link path argument to std::filesystem::create_symlink
98099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
99099543e4SBrad Bishop  */
100099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget,
101099543e4SBrad Bishop                const std::filesystem::path& linkPath,
102099543e4SBrad Bishop                const ErrorCallbackType& errorCallback)
103099543e4SBrad Bishop {
104099543e4SBrad Bishop     std::error_code ec;
105099543e4SBrad Bishop 
106099543e4SBrad Bishop     // remove files with the same name as the symlink to be created,
107099543e4SBrad Bishop     // otherwise symlink will fail with EEXIST.
108099543e4SBrad Bishop     if (!std::filesystem::remove(linkPath, ec))
109099543e4SBrad Bishop     {
110099543e4SBrad Bishop         if (ec)
111099543e4SBrad Bishop         {
112099543e4SBrad Bishop             makeCallback(errorCallback, linkPath, ec);
113099543e4SBrad Bishop             return;
114099543e4SBrad Bishop         }
115099543e4SBrad Bishop     }
116099543e4SBrad Bishop 
117099543e4SBrad Bishop     std::filesystem::create_symlink(linkTarget, linkPath, ec);
118099543e4SBrad Bishop     if (ec)
119099543e4SBrad Bishop     {
120099543e4SBrad Bishop         makeCallback(errorCallback, linkPath, ec);
121099543e4SBrad Bishop         return;
122099543e4SBrad Bishop     }
123099543e4SBrad Bishop }
124099543e4SBrad Bishop 
125099543e4SBrad Bishop /**
126099543e4SBrad Bishop  * @brief Find host firmware blob files that need well-known names
127099543e4SBrad Bishop  *
128099543e4SBrad Bishop  * The IBM host firmware runtime looks for data and/or additional code while
129099543e4SBrad Bishop  * bootstraping in files with well-known names.  findLinks uses the provided
130099543e4SBrad Bishop  * extensions argument to find host firmware blob files that require a
131099543e4SBrad Bishop  * well-known name.  When a blob is found, issue the provided callback
132099543e4SBrad Bishop  * (typically a function that will write a symlink).
133099543e4SBrad Bishop  *
134099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
135099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
136099543e4SBrad Bishop  * @param[in] extentions The extensions of the firmware blob files denote a
137099543e4SBrad Bishop  * host firmware blob file requires a well-known name.
138099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
139099543e4SBrad Bishop  * @param[in] linkCallback A callback made when host firmware blob files
140099543e4SBrad Bishop  * needing a well known name are found.
141099543e4SBrad Bishop  */
142099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory,
143099543e4SBrad Bishop                const std::vector<std::string>& extensions,
144099543e4SBrad Bishop                const ErrorCallbackType& errorCallback,
145099543e4SBrad Bishop                const LinkCallbackType& linkCallback)
146099543e4SBrad Bishop {
147099543e4SBrad Bishop     std::error_code ec;
148099543e4SBrad Bishop     std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory,
149099543e4SBrad Bishop                                                           ec);
150099543e4SBrad Bishop     if (ec)
151099543e4SBrad Bishop     {
152099543e4SBrad Bishop         makeCallback(errorCallback, hostFirmwareDirectory, ec);
153099543e4SBrad Bishop         return;
154099543e4SBrad Bishop     }
155099543e4SBrad Bishop 
156fdc91fa0SAdriana Kobylak     // Create a symlink from HBB to the corresponding LID file if it exists
157fdc91fa0SAdriana Kobylak     static const auto hbbLid = "81e0065a.lid";
158fdc91fa0SAdriana Kobylak     auto hbbLidPath = hostFirmwareDirectory / hbbLid;
159fdc91fa0SAdriana Kobylak     if (std::filesystem::exists(hbbLidPath))
160fdc91fa0SAdriana Kobylak     {
161fdc91fa0SAdriana Kobylak         static const auto hbbName = "HBB";
162fdc91fa0SAdriana Kobylak         auto hbbLinkPath = hostFirmwareDirectory / hbbName;
163fdc91fa0SAdriana Kobylak         makeCallback(linkCallback, hbbLid, hbbLinkPath, errorCallback);
164fdc91fa0SAdriana Kobylak     }
165fdc91fa0SAdriana Kobylak 
166099543e4SBrad Bishop     for (; directoryIterator != std::filesystem::end(directoryIterator);
167099543e4SBrad Bishop          directoryIterator.increment(ec))
168099543e4SBrad Bishop     {
169099543e4SBrad Bishop         const auto& file = directoryIterator->path();
170099543e4SBrad Bishop         if (ec)
171099543e4SBrad Bishop         {
172099543e4SBrad Bishop             makeCallback(errorCallback, file, ec);
173099543e4SBrad Bishop             // quit here if the increment call failed otherwise the loop may
174099543e4SBrad Bishop             // never finish
175099543e4SBrad Bishop             break;
176099543e4SBrad Bishop         }
177099543e4SBrad Bishop 
178099543e4SBrad Bishop         if (std::find(extensions.begin(), extensions.end(), file.extension()) ==
179099543e4SBrad Bishop             extensions.end())
180099543e4SBrad Bishop         {
181099543e4SBrad Bishop             // this file doesn't have an extension or doesn't match any of the
182099543e4SBrad Bishop             // provided extensions.
183099543e4SBrad Bishop             continue;
184099543e4SBrad Bishop         }
185099543e4SBrad Bishop 
186099543e4SBrad Bishop         auto linkPath(file.parent_path().append(
187099543e4SBrad Bishop             static_cast<const std::string&>(file.stem())));
188099543e4SBrad Bishop 
189099543e4SBrad Bishop         makeCallback(linkCallback, file.filename(), linkPath, errorCallback);
190099543e4SBrad Bishop     }
191099543e4SBrad Bishop }
192099543e4SBrad Bishop 
193099543e4SBrad Bishop /**
194099543e4SBrad Bishop  * @brief Make callbacks on
195099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
196099543e4SBrad Bishop  *
197099543e4SBrad Bishop  * Look for an instance of
198099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
199099543e4SBrad Bishop  * argument and if found, issue the provided callback.
200099543e4SBrad Bishop  *
201099543e4SBrad Bishop  * @param[in] interfacesAndProperties the interfaces in which to look for an
202099543e4SBrad Bishop  * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem
203099543e4SBrad Bishop  * @param[in] callback the user callback to make if
204099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
205099543e4SBrad Bishop  * interfacesAndProperties
206099543e4SBrad Bishop  * @return true if interfacesAndProperties contained an instance of
207099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
208099543e4SBrad Bishop  */
209099543e4SBrad Bishop bool maybeCall(const std::map<std::string,
210099543e4SBrad Bishop                               std::map<std::string,
211099543e4SBrad Bishop                                        std::variant<std::vector<std::string>>>>&
212099543e4SBrad Bishop                    interfacesAndProperties,
213099543e4SBrad Bishop                const MaybeCallCallbackType& callback)
214099543e4SBrad Bishop {
215099543e4SBrad Bishop     using namespace std::string_literals;
216099543e4SBrad Bishop 
217099543e4SBrad Bishop     static const auto interfaceName =
218099543e4SBrad Bishop         "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s;
219099543e4SBrad Bishop     auto interfaceIterator = interfacesAndProperties.find(interfaceName);
220099543e4SBrad Bishop     if (interfaceIterator == interfacesAndProperties.cend())
221099543e4SBrad Bishop     {
222099543e4SBrad Bishop         // IBMCompatibleSystem interface not found, so instruct the caller to
223099543e4SBrad Bishop         // keep waiting or try again later.
224099543e4SBrad Bishop         return false;
225099543e4SBrad Bishop     }
226099543e4SBrad Bishop     auto propertyIterator = interfaceIterator->second.find("Names"s);
227099543e4SBrad Bishop     if (propertyIterator == interfaceIterator->second.cend())
228099543e4SBrad Bishop     {
229099543e4SBrad Bishop         // The interface exists but the property doesn't.  This is a bug in the
230099543e4SBrad Bishop         // IBMCompatibleSystem implementation.  The caller should not try
231099543e4SBrad Bishop         // again.
232099543e4SBrad Bishop         std::cerr << "Names property not implemented on " << interfaceName
233099543e4SBrad Bishop                   << "\n";
234099543e4SBrad Bishop         return true;
235099543e4SBrad Bishop     }
236099543e4SBrad Bishop 
237099543e4SBrad Bishop     const auto& ibmCompatibleSystem =
238099543e4SBrad Bishop         std::get<std::vector<std::string>>(propertyIterator->second);
239099543e4SBrad Bishop     if (callback)
240099543e4SBrad Bishop     {
241099543e4SBrad Bishop         callback(ibmCompatibleSystem);
242099543e4SBrad Bishop     }
243099543e4SBrad Bishop 
244099543e4SBrad Bishop     // IBMCompatibleSystem found and callback issued.
245099543e4SBrad Bishop     return true;
246099543e4SBrad Bishop }
247099543e4SBrad Bishop 
248099543e4SBrad Bishop /**
249099543e4SBrad Bishop  * @brief Make callbacks on
250099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
251099543e4SBrad Bishop  *
252099543e4SBrad Bishop  * Look for an instance of
253099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
254099543e4SBrad Bishop  * argument and if found, issue the provided callback.
255099543e4SBrad Bishop  *
256099543e4SBrad Bishop  * @param[in] message the DBus message in which to look for an instance of
257099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
258099543e4SBrad Bishop  * @param[in] callback the user callback to make if
259099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
260099543e4SBrad Bishop  * message
261099543e4SBrad Bishop  * @return true if message contained an instance of
262099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
263099543e4SBrad Bishop  */
264099543e4SBrad Bishop bool maybeCallMessage(sdbusplus::message::message& message,
265099543e4SBrad Bishop                       const MaybeCallCallbackType& callback)
266099543e4SBrad Bishop {
267099543e4SBrad Bishop     std::map<std::string,
268099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
269099543e4SBrad Bishop         interfacesAndProperties;
270099543e4SBrad Bishop     sdbusplus::message::object_path _;
271099543e4SBrad Bishop     message.read(_, interfacesAndProperties);
272099543e4SBrad Bishop     return maybeCall(interfacesAndProperties, callback);
273099543e4SBrad Bishop }
274099543e4SBrad Bishop 
275099543e4SBrad Bishop /**
276099543e4SBrad Bishop  * @brief Determine system support for host firmware well-known names.
277099543e4SBrad Bishop  *
278099543e4SBrad Bishop  * Using the provided extensionMap and
279099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if
280099543e4SBrad Bishop  * well-known names for host firmare blob files are necessary and if so, create
281099543e4SBrad Bishop  * them.
282099543e4SBrad Bishop  *
283099543e4SBrad Bishop  * @param[in] extensionMap a map of
284099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
285099543e4SBrad Bishop  * file extensions.
286099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
287099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
288099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
289099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
290099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
291099543e4SBrad Bishop  */
292099543e4SBrad Bishop void maybeMakeLinks(
293099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
294099543e4SBrad Bishop     const std::filesystem::path& hostFirmwareDirectory,
295099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
296099543e4SBrad Bishop     const ErrorCallbackType& errorCallback)
297099543e4SBrad Bishop {
298099543e4SBrad Bishop     std::vector<std::string> extensions;
299099543e4SBrad Bishop     if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
300099543e4SBrad Bishop                                             extensions))
301099543e4SBrad Bishop     {
302099543e4SBrad Bishop         findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink);
303099543e4SBrad Bishop     }
304099543e4SBrad Bishop }
305099543e4SBrad Bishop 
306099543e4SBrad Bishop /**
307099543e4SBrad Bishop  * @brief process host firmware
308099543e4SBrad Bishop  *
309099543e4SBrad Bishop  * Allocate a callback context and register for DBus.ObjectManager Interfaces
310099543e4SBrad Bishop  * added signals from entity manager.
311099543e4SBrad Bishop  *
312099543e4SBrad Bishop  * Check the current entity manager object tree for a
313099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity
314099543e4SBrad Bishop  * manager will be dbus activated if it is not running).  If one is found,
315099543e4SBrad Bishop  * determine if symlinks need to be created and create them.  Instruct the
316099543e4SBrad Bishop  * program event loop to exit.
317099543e4SBrad Bishop  *
318099543e4SBrad Bishop  * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
319099543e4SBrad Bishop  * found return the callback context to main, where the program will sleep
320099543e4SBrad Bishop  * until the callback is invoked one or more times and instructs the program
321099543e4SBrad Bishop  * event loop to exit when
322099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added.
323099543e4SBrad Bishop  *
324099543e4SBrad Bishop  * @param[in] bus a DBus client connection
325099543e4SBrad Bishop  * @param[in] extensionMap a map of
326099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
327099543e4SBrad Bishop  * file extensions.
328099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which processHostFirmware
329099543e4SBrad Bishop  * should look for blob files.
330099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
331099543e4SBrad Bishop  * @param[in] loop a program event loop
332099543e4SBrad Bishop  * @return nullptr if an instance of
333099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a
334099543e4SBrad Bishop  * pointer to an sdbusplus match object.
335099543e4SBrad Bishop  */
336099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware(
337099543e4SBrad Bishop     sdbusplus::bus::bus& bus,
338099543e4SBrad Bishop     std::map<std::string, std::vector<std::string>> extensionMap,
339099543e4SBrad Bishop     std::filesystem::path hostFirmwareDirectory,
340099543e4SBrad Bishop     ErrorCallbackType errorCallback, sdeventplus::Event& loop)
341099543e4SBrad Bishop {
342099543e4SBrad Bishop     // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't
343099543e4SBrad Bishop     // be transfered to the match callback because they are needed in the non
344099543e4SBrad Bishop     // async part of this function below, so they need to be moved to the heap.
345099543e4SBrad Bishop     auto pExtensionMap =
346099543e4SBrad Bishop         std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
347099543e4SBrad Bishop     auto pHostFirmwareDirectory =
348099543e4SBrad Bishop         std::make_shared<decltype(hostFirmwareDirectory)>(
349099543e4SBrad Bishop             std::move(hostFirmwareDirectory));
350099543e4SBrad Bishop     auto pErrorCallback =
351099543e4SBrad Bishop         std::make_shared<decltype(errorCallback)>(std::move(errorCallback));
352099543e4SBrad Bishop 
353099543e4SBrad Bishop     // register for a callback in case the IBMCompatibleSystem interface has
354099543e4SBrad Bishop     // not yet been published by entity manager.
355099543e4SBrad Bishop     auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>(
356099543e4SBrad Bishop         bus,
357099543e4SBrad Bishop         sdbusplus::bus::match::rules::interfacesAdded() +
358099543e4SBrad Bishop             sdbusplus::bus::match::rules::sender(
359099543e4SBrad Bishop                 "xyz.openbmc_project.EntityManager"),
360099543e4SBrad Bishop         [pExtensionMap, pHostFirmwareDirectory, pErrorCallback,
361099543e4SBrad Bishop          &loop](auto& message) {
362099543e4SBrad Bishop             // bind the extension map, host firmware directory, and error
363099543e4SBrad Bishop             // callback to the maybeMakeLinks function.
364099543e4SBrad Bishop             auto maybeMakeLinksWithArgsBound =
365099543e4SBrad Bishop                 std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
366099543e4SBrad Bishop                           std::cref(*pHostFirmwareDirectory),
367099543e4SBrad Bishop                           std::placeholders::_1, std::cref(*pErrorCallback));
368099543e4SBrad Bishop 
369099543e4SBrad Bishop             // if the InterfacesAdded message contains an an instance of
370099543e4SBrad Bishop             // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to
371099543e4SBrad Bishop             // see if links are necessary on this system and if so, create
372099543e4SBrad Bishop             // them.
373099543e4SBrad Bishop             if (maybeCallMessage(message, maybeMakeLinksWithArgsBound))
374099543e4SBrad Bishop             {
375099543e4SBrad Bishop                 // The IBMCompatibleSystem interface was found and the links
376099543e4SBrad Bishop                 // were created if applicable.  Instruct the event loop /
377099543e4SBrad Bishop                 // subcommand to exit.
378099543e4SBrad Bishop                 loop.exit(0);
379099543e4SBrad Bishop             }
380099543e4SBrad Bishop         });
381099543e4SBrad Bishop 
382099543e4SBrad Bishop     // now that we'll get a callback in the event of an InterfacesAdded signal
383099543e4SBrad Bishop     // (potentially containing
384099543e4SBrad Bishop     // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity
385099543e4SBrad Bishop     // manager if it isn't running and enumerate its objects
386099543e4SBrad Bishop     auto getManagedObjects = bus.new_method_call(
387099543e4SBrad Bishop         "xyz.openbmc_project.EntityManager", "/",
388099543e4SBrad Bishop         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
389099543e4SBrad Bishop     std::map<std::string,
390099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
391099543e4SBrad Bishop         interfacesAndProperties;
392099543e4SBrad Bishop     std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
393099543e4SBrad Bishop         objects;
394*c79fa915SAdriana Kobylak     try
395*c79fa915SAdriana Kobylak     {
396*c79fa915SAdriana Kobylak         auto reply = bus.call(getManagedObjects);
397099543e4SBrad Bishop         reply.read(objects);
398*c79fa915SAdriana Kobylak     }
399*c79fa915SAdriana Kobylak     catch (const sdbusplus::exception::SdBusError& e)
400*c79fa915SAdriana Kobylak     {
401*c79fa915SAdriana Kobylak         // Error querying the EntityManager interface. Return the match to have
402*c79fa915SAdriana Kobylak         // the callback run if/when the interface appears in D-Bus.
403*c79fa915SAdriana Kobylak         return interfacesAddedMatch;
404*c79fa915SAdriana Kobylak     }
405099543e4SBrad Bishop 
406099543e4SBrad Bishop     // bind the extension map, host firmware directory, and error callback to
407099543e4SBrad Bishop     // the maybeMakeLinks function.
408099543e4SBrad Bishop     auto maybeMakeLinksWithArgsBound =
409099543e4SBrad Bishop         std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
410099543e4SBrad Bishop                   std::cref(*pHostFirmwareDirectory), std::placeholders::_1,
411099543e4SBrad Bishop                   std::cref(*pErrorCallback));
412099543e4SBrad Bishop 
413099543e4SBrad Bishop     for (const auto& pair : objects)
414099543e4SBrad Bishop     {
415099543e4SBrad Bishop         std::tie(std::ignore, interfacesAndProperties) = pair;
416099543e4SBrad Bishop         // if interfacesAndProperties contains an an instance of
417099543e4SBrad Bishop         // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see
418099543e4SBrad Bishop         // if links are necessary on this system and if so, create them
419099543e4SBrad Bishop         if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound))
420099543e4SBrad Bishop         {
421099543e4SBrad Bishop             // The IBMCompatibleSystem interface is already on the bus and the
422099543e4SBrad Bishop             // links were created if applicable.  Instruct the event loop to
423099543e4SBrad Bishop             // exit.
424099543e4SBrad Bishop             loop.exit(0);
425099543e4SBrad Bishop             // The match object isn't needed anymore, so destroy it on return.
426099543e4SBrad Bishop             return nullptr;
427099543e4SBrad Bishop         }
428099543e4SBrad Bishop     }
429099543e4SBrad Bishop 
430099543e4SBrad Bishop     // The IBMCompatibleSystem interface has not yet been published.  Move
431099543e4SBrad Bishop     // ownership of the match callback to the caller.
432099543e4SBrad Bishop     return interfacesAddedMatch;
433099543e4SBrad Bishop }
434099543e4SBrad Bishop } // namespace process_hostfirmware
435099543e4SBrad Bishop } // namespace functions
436