xref: /openbmc/phosphor-objmgr/src/main.cpp (revision 41ad83808e8b1c5fbbf5c0e9fcb38fe8b23f7e4e)
1a80a3af0SAndrew Geissler #include "associations.hpp"
2aba14d3dSWilly Tu #include "handler.hpp"
33b025e69SAndrew Geissler #include "processing.hpp"
435396c10SMatt Spinler #include "types.hpp"
5dd945861SMatt Spinler 
660520631SEd Tanous #include <tinyxml2.h>
760520631SEd Tanous 
821c60595SEd Tanous #include <boost/asio/io_context.hpp>
921c60595SEd Tanous #include <boost/asio/signal_set.hpp>
1060520631SEd Tanous #include <boost/container/flat_map.hpp>
1160520631SEd Tanous #include <sdbusplus/asio/connection.hpp>
1260520631SEd Tanous #include <sdbusplus/asio/object_server.hpp>
13b15df6b2SKonstantin Aladyshev #include <xyz/openbmc_project/Common/error.hpp>
1460520631SEd Tanous 
152352088eSBrad Bishop #include <atomic>
162352088eSBrad Bishop #include <chrono>
17ea119463SBrad Bishop #include <exception>
182352088eSBrad Bishop #include <iomanip>
192352088eSBrad Bishop #include <iostream>
20f6ebfc73SBrandon Kim #include <string>
21f6ebfc73SBrandon Kim #include <string_view>
221f62380aSBrad Bishop #include <utility>
232352088eSBrad Bishop 
24e2359fb7SMatt Spinler AssociationMaps associationMaps;
25937a232eSMatt Spinler 
updateOwners(sdbusplus::asio::connection * conn,boost::container::flat_map<std::string,std::string> & owners,const std::string & newObject)26a098a37aSBrad Bishop void updateOwners(sdbusplus::asio::connection* conn,
2760520631SEd Tanous                   boost::container::flat_map<std::string, std::string>& owners,
28a098a37aSBrad Bishop                   const std::string& newObject)
2960520631SEd Tanous {
3086d2880eSBrad Bishop     if (newObject.starts_with(":"))
3160520631SEd Tanous     {
3260520631SEd Tanous         return;
3360520631SEd Tanous     }
3460520631SEd Tanous     conn->async_method_call(
35a098a37aSBrad Bishop         [&, newObject](const boost::system::error_code ec,
3660520631SEd Tanous                        const std::string& nameOwner) {
3760520631SEd Tanous             if (ec)
3860520631SEd Tanous             {
399052ebd3SPatrick Williams                 std::cerr << "Error getting owner of " << newObject << " : "
409052ebd3SPatrick Williams                           << ec << "\n";
4160520631SEd Tanous                 return;
4260520631SEd Tanous             }
43a098a37aSBrad Bishop             owners[nameOwner] = newObject;
4460520631SEd Tanous         },
4560520631SEd Tanous         "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
46a098a37aSBrad Bishop         newObject);
4760520631SEd Tanous }
4860520631SEd Tanous 
sendIntrospectionCompleteSignal(sdbusplus::asio::connection * systemBus,const std::string & processName)49a098a37aSBrad Bishop void sendIntrospectionCompleteSignal(sdbusplus::asio::connection* systemBus,
50a098a37aSBrad Bishop                                      const std::string& processName)
5160520631SEd Tanous {
5260520631SEd Tanous     // TODO(ed) This signal doesn't get exposed properly in the
5360520631SEd Tanous     // introspect right now.  Find out how to register signals in
5460520631SEd Tanous     // sdbusplus
55cc8070baSPatrick Williams     sdbusplus::message_t m = systemBus->new_signal(
56a02cd54cSBrad Bishop         "/xyz/openbmc_project/object_mapper",
57a02cd54cSBrad Bishop         "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
58a098a37aSBrad Bishop     m.append(processName);
5960520631SEd Tanous     m.signal_send();
6060520631SEd Tanous }
6160520631SEd Tanous 
6260520631SEd Tanous struct InProgressIntrospect
6360520631SEd Tanous {
641f62380aSBrad Bishop     InProgressIntrospect() = delete;
651f62380aSBrad Bishop     InProgressIntrospect(const InProgressIntrospect&) = delete;
661f62380aSBrad Bishop     InProgressIntrospect(InProgressIntrospect&&) = delete;
671f62380aSBrad Bishop     InProgressIntrospect& operator=(const InProgressIntrospect&) = delete;
681f62380aSBrad Bishop     InProgressIntrospect& operator=(InProgressIntrospect&&) = delete;
InProgressIntrospectInProgressIntrospect6960520631SEd Tanous     InProgressIntrospect(
70a098a37aSBrad Bishop         sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
71a098a37aSBrad Bishop         const std::string& processName, AssociationMaps& am
72d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
73aecabe86SMatt Spinler         ,
7460520631SEd Tanous         std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
75a098a37aSBrad Bishop             globalStartTime
76aecabe86SMatt Spinler #endif
77aecabe86SMatt Spinler         ) :
789052ebd3SPatrick Williams         systemBus(systemBus), io(io), processName(processName), assocMaps(am)
79d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
80aecabe86SMatt Spinler         ,
811f62380aSBrad Bishop         globalStartTime(std::move(globalStartTime)),
82a098a37aSBrad Bishop         processStartTime(std::chrono::steady_clock::now())
83aecabe86SMatt Spinler #endif
842352088eSBrad Bishop     {}
~InProgressIntrospectInProgressIntrospect8560520631SEd Tanous     ~InProgressIntrospect()
8660520631SEd Tanous     {
87ea119463SBrad Bishop         try
88ea119463SBrad Bishop         {
89a098a37aSBrad Bishop             sendIntrospectionCompleteSignal(systemBus, processName);
90d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
9160520631SEd Tanous             std::chrono::duration<float> diff =
92a098a37aSBrad Bishop                 std::chrono::steady_clock::now() - processStartTime;
93a098a37aSBrad Bishop             std::cout << std::setw(50) << processName << " scan took "
9460520631SEd Tanous                       << diff.count() << " seconds\n";
9560520631SEd Tanous 
9660520631SEd Tanous             // If we're the last outstanding caller globally, calculate the
9760520631SEd Tanous             // time it took
98a098a37aSBrad Bishop             if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
9960520631SEd Tanous             {
100a098a37aSBrad Bishop                 diff = std::chrono::steady_clock::now() - *globalStartTime;
10160520631SEd Tanous                 std::cout << "Total scan took " << diff.count()
10260520631SEd Tanous                           << " seconds to complete\n";
10360520631SEd Tanous             }
104aecabe86SMatt Spinler #endif
10560520631SEd Tanous         }
106ea119463SBrad Bishop         catch (const std::exception& e)
107ea119463SBrad Bishop         {
108ea119463SBrad Bishop             std::cerr
109ea119463SBrad Bishop                 << "Terminating, unhandled exception while introspecting: "
110ea119463SBrad Bishop                 << e.what() << "\n";
111ea119463SBrad Bishop             std::terminate();
112ea119463SBrad Bishop         }
113ea119463SBrad Bishop         catch (...)
114ea119463SBrad Bishop         {
115ea119463SBrad Bishop             std::cerr
116ea119463SBrad Bishop                 << "Terminating, unhandled exception while introspecting\n";
117ea119463SBrad Bishop             std::terminate();
118ea119463SBrad Bishop         }
119ea119463SBrad Bishop     }
120a098a37aSBrad Bishop     sdbusplus::asio::connection* systemBus;
12121c60595SEd Tanous     boost::asio::io_context& io;
122a098a37aSBrad Bishop     std::string processName;
12311401e2eSMatt Spinler     AssociationMaps& assocMaps;
124d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
12560520631SEd Tanous     std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
126a098a37aSBrad Bishop         globalStartTime;
127a098a37aSBrad Bishop     std::chrono::time_point<std::chrono::steady_clock> processStartTime;
128aecabe86SMatt Spinler #endif
12960520631SEd Tanous };
13060520631SEd Tanous 
doAssociations(boost::asio::io_context & io,sdbusplus::asio::connection * systemBus,InterfaceMapType & interfaceMap,sdbusplus::asio::object_server & objectServer,const std::string & processName,const std::string & path,int timeoutRetries=0)1315b4357daSKallas, Pawel void doAssociations(boost::asio::io_context& io,
1325b4357daSKallas, Pawel                     sdbusplus::asio::connection* systemBus,
133a098a37aSBrad Bishop                     InterfaceMapType& interfaceMap,
13460520631SEd Tanous                     sdbusplus::asio::object_server& objectServer,
135bb40bd36SAdrian Ambrożewicz                     const std::string& processName, const std::string& path,
136bb40bd36SAdrian Ambrożewicz                     int timeoutRetries = 0)
13760520631SEd Tanous {
138bb40bd36SAdrian Ambrożewicz     constexpr int maxTimeoutRetries = 3;
139a098a37aSBrad Bishop     systemBus->async_method_call(
1405b4357daSKallas, Pawel         [&io, &objectServer, path, processName, &interfaceMap, systemBus,
141bb40bd36SAdrian Ambrożewicz          timeoutRetries](
142937a232eSMatt Spinler             const boost::system::error_code ec,
1432bb2d6baSPatrick Williams             const std::variant<std::vector<Association>>& variantAssociations) {
14460520631SEd Tanous             if (ec)
14560520631SEd Tanous             {
146bb40bd36SAdrian Ambrożewicz                 if (ec.value() == boost::system::errc::timed_out &&
147bb40bd36SAdrian Ambrożewicz                     timeoutRetries < maxTimeoutRetries)
148bb40bd36SAdrian Ambrożewicz                 {
1495b4357daSKallas, Pawel                     doAssociations(io, systemBus, interfaceMap, objectServer,
150bb40bd36SAdrian Ambrożewicz                                    processName, path, timeoutRetries + 1);
151bb40bd36SAdrian Ambrożewicz                     return;
152bb40bd36SAdrian Ambrożewicz                 }
15360520631SEd Tanous                 std::cerr << "Error getting associations from " << path << "\n";
15460520631SEd Tanous             }
15560520631SEd Tanous             std::vector<Association> associations =
156b05bc12cSPatrick Williams                 std::get<std::vector<Association>>(variantAssociations);
1579052ebd3SPatrick Williams             associationChanged(io, objectServer, associations, path,
1589052ebd3SPatrick Williams                                processName, interfaceMap, associationMaps);
15960520631SEd Tanous         },
16060520631SEd Tanous         processName, path, "org.freedesktop.DBus.Properties", "Get",
161d0cf9428SJohn Wang         assocDefsInterface, assocDefsProperty);
16260520631SEd Tanous }
16360520631SEd Tanous 
doIntrospect(boost::asio::io_context & io,sdbusplus::asio::connection * systemBus,const std::shared_ptr<InProgressIntrospect> & transaction,InterfaceMapType & interfaceMap,sdbusplus::asio::object_server & objectServer,const std::string & path,int timeoutRetries=0)1645b4357daSKallas, Pawel void doIntrospect(boost::asio::io_context& io,
1655b4357daSKallas, Pawel                   sdbusplus::asio::connection* systemBus,
1661f62380aSBrad Bishop                   const std::shared_ptr<InProgressIntrospect>& transaction,
167a098a37aSBrad Bishop                   InterfaceMapType& interfaceMap,
16860520631SEd Tanous                   sdbusplus::asio::object_server& objectServer,
1691f62380aSBrad Bishop                   const std::string& path, int timeoutRetries = 0)
17060520631SEd Tanous {
171c52be0d2SVernon Mauery     constexpr int maxTimeoutRetries = 3;
172a098a37aSBrad Bishop     systemBus->async_method_call(
1735b4357daSKallas, Pawel         [&io, &interfaceMap, &objectServer, transaction, path, systemBus,
174c52be0d2SVernon Mauery          timeoutRetries](const boost::system::error_code ec,
175a098a37aSBrad Bishop                          const std::string& introspectXml) {
17660520631SEd Tanous             if (ec)
17760520631SEd Tanous             {
178c52be0d2SVernon Mauery                 if (ec.value() == boost::system::errc::timed_out &&
179c52be0d2SVernon Mauery                     timeoutRetries < maxTimeoutRetries)
180c52be0d2SVernon Mauery                 {
1815b4357daSKallas, Pawel                     doIntrospect(io, systemBus, transaction, interfaceMap,
182c52be0d2SVernon Mauery                                  objectServer, path, timeoutRetries + 1);
183c52be0d2SVernon Mauery                     return;
184c52be0d2SVernon Mauery                 }
18560520631SEd Tanous                 std::cerr << "Introspect call failed with error: " << ec << ", "
18660520631SEd Tanous                           << ec.message()
187a098a37aSBrad Bishop                           << " on process: " << transaction->processName
18860520631SEd Tanous                           << " path: " << path << "\n";
18960520631SEd Tanous                 return;
19060520631SEd Tanous             }
19160520631SEd Tanous 
19260520631SEd Tanous             tinyxml2::XMLDocument doc;
19360520631SEd Tanous 
194a098a37aSBrad Bishop             tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
19560520631SEd Tanous             if (e != tinyxml2::XMLError::XML_SUCCESS)
19660520631SEd Tanous             {
19760520631SEd Tanous                 std::cerr << "XML parsing failed\n";
19860520631SEd Tanous                 return;
19960520631SEd Tanous             }
20060520631SEd Tanous 
20160520631SEd Tanous             tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
20260520631SEd Tanous             if (pRoot == nullptr)
20360520631SEd Tanous             {
20460520631SEd Tanous                 std::cerr << "XML document did not contain any data\n";
20560520631SEd Tanous                 return;
20660520631SEd Tanous             }
207a098a37aSBrad Bishop             auto& thisPathMap = interfaceMap[path];
2089052ebd3SPatrick Williams             tinyxml2::XMLElement* pElement =
2099052ebd3SPatrick Williams                 pRoot->FirstChildElement("interface");
21060520631SEd Tanous             while (pElement != nullptr)
21160520631SEd Tanous             {
212a098a37aSBrad Bishop                 const char* ifaceName = pElement->Attribute("name");
213a098a37aSBrad Bishop                 if (ifaceName == nullptr)
21460520631SEd Tanous                 {
21560520631SEd Tanous                     continue;
21660520631SEd Tanous                 }
21760520631SEd Tanous 
218a098a37aSBrad Bishop                 thisPathMap[transaction->processName].emplace(ifaceName);
219d4dd96a0SEd Tanous 
220a098a37aSBrad Bishop                 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
22160520631SEd Tanous                 {
2225b4357daSKallas, Pawel                     doAssociations(io, systemBus, interfaceMap, objectServer,
223a098a37aSBrad Bishop                                    transaction->processName, path);
22460520631SEd Tanous                 }
22560520631SEd Tanous 
22660520631SEd Tanous                 pElement = pElement->NextSiblingElement("interface");
22760520631SEd Tanous             }
22860520631SEd Tanous 
22911401e2eSMatt Spinler             // Check if this new path has a pending association that can
23011401e2eSMatt Spinler             // now be completed.
2315b4357daSKallas, Pawel             checkIfPendingAssociation(io, path, interfaceMap,
23211401e2eSMatt Spinler                                       transaction->assocMaps, objectServer);
23311401e2eSMatt Spinler 
23460520631SEd Tanous             pElement = pRoot->FirstChildElement("node");
23560520631SEd Tanous             while (pElement != nullptr)
23660520631SEd Tanous             {
237a098a37aSBrad Bishop                 const char* childPath = pElement->Attribute("name");
238a098a37aSBrad Bishop                 if (childPath != nullptr)
23960520631SEd Tanous                 {
240a098a37aSBrad Bishop                     std::string parentPath(path);
241a098a37aSBrad Bishop                     if (parentPath == "/")
24260520631SEd Tanous                     {
243a098a37aSBrad Bishop                         parentPath.clear();
24460520631SEd Tanous                     }
24560520631SEd Tanous 
2465b4357daSKallas, Pawel                     doIntrospect(io, systemBus, transaction, interfaceMap,
247a098a37aSBrad Bishop                                  objectServer, parentPath + "/" + childPath);
24860520631SEd Tanous                 }
24960520631SEd Tanous                 pElement = pElement->NextSiblingElement("node");
25060520631SEd Tanous             }
25160520631SEd Tanous         },
252a098a37aSBrad Bishop         transaction->processName, path, "org.freedesktop.DBus.Introspectable",
25360520631SEd Tanous         "Introspect");
25460520631SEd Tanous }
25560520631SEd Tanous 
startNewIntrospect(sdbusplus::asio::connection * systemBus,boost::asio::io_context & io,InterfaceMapType & interfaceMap,const std::string & processName,AssociationMaps & assocMaps,std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>> globalStartTime,sdbusplus::asio::object_server & objectServer)256a098a37aSBrad Bishop void startNewIntrospect(
257a098a37aSBrad Bishop     sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
258a098a37aSBrad Bishop     InterfaceMapType& interfaceMap, const std::string& processName,
25911401e2eSMatt Spinler     AssociationMaps& assocMaps,
260d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
26160520631SEd Tanous     std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
262a098a37aSBrad Bishop         globalStartTime,
263aecabe86SMatt Spinler #endif
26460520631SEd Tanous     sdbusplus::asio::object_server& objectServer)
26560520631SEd Tanous {
2661e94e60bSBrad Bishop     if (needToIntrospect(processName))
26760520631SEd Tanous     {
26860520631SEd Tanous         std::shared_ptr<InProgressIntrospect> transaction =
2699052ebd3SPatrick Williams             std::make_shared<InProgressIntrospect>(
2709052ebd3SPatrick Williams                 systemBus, io, processName, assocMaps
271d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
272aecabe86SMatt Spinler                 ,
273a098a37aSBrad Bishop                 globalStartTime
274aecabe86SMatt Spinler #endif
275aecabe86SMatt Spinler             );
27660520631SEd Tanous 
2775b4357daSKallas, Pawel         doIntrospect(io, systemBus, transaction, interfaceMap, objectServer,
2785b4357daSKallas, Pawel                      "/");
27960520631SEd Tanous     }
28060520631SEd Tanous }
28160520631SEd Tanous 
doListNames(boost::asio::io_context & io,InterfaceMapType & interfaceMap,sdbusplus::asio::connection * systemBus,boost::container::flat_map<std::string,std::string> & nameOwners,AssociationMaps & assocMaps,sdbusplus::asio::object_server & objectServer)28260520631SEd Tanous void doListNames(
283a098a37aSBrad Bishop     boost::asio::io_context& io, InterfaceMapType& interfaceMap,
284a098a37aSBrad Bishop     sdbusplus::asio::connection* systemBus,
285a098a37aSBrad Bishop     boost::container::flat_map<std::string, std::string>& nameOwners,
28611401e2eSMatt Spinler     AssociationMaps& assocMaps, sdbusplus::asio::object_server& objectServer)
28760520631SEd Tanous {
288a098a37aSBrad Bishop     systemBus->async_method_call(
289a098a37aSBrad Bishop         [&io, &interfaceMap, &nameOwners, &objectServer, systemBus,
29011401e2eSMatt Spinler          &assocMaps](const boost::system::error_code ec,
291a098a37aSBrad Bishop                      std::vector<std::string> processNames) {
29260520631SEd Tanous             if (ec)
29360520631SEd Tanous             {
29460520631SEd Tanous                 std::cerr << "Error getting names: " << ec << "\n";
29560520631SEd Tanous                 std::exit(EXIT_FAILURE);
29660520631SEd Tanous                 return;
29760520631SEd Tanous             }
29860520631SEd Tanous             // Try to make startup consistent
299a098a37aSBrad Bishop             std::sort(processNames.begin(), processNames.end());
300d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
30160520631SEd Tanous             std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
302a098a37aSBrad Bishop                 globalStartTime = std::make_shared<
30360520631SEd Tanous                     std::chrono::time_point<std::chrono::steady_clock>>(
30460520631SEd Tanous                     std::chrono::steady_clock::now());
305aecabe86SMatt Spinler #endif
306a098a37aSBrad Bishop             for (const std::string& processName : processNames)
30760520631SEd Tanous             {
3081e94e60bSBrad Bishop                 if (needToIntrospect(processName))
30960520631SEd Tanous                 {
310a098a37aSBrad Bishop                     startNewIntrospect(systemBus, io, interfaceMap, processName,
311a098a37aSBrad Bishop                                        assocMaps,
312d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
313a098a37aSBrad Bishop                                        globalStartTime,
314aecabe86SMatt Spinler #endif
31560520631SEd Tanous                                        objectServer);
316a098a37aSBrad Bishop                     updateOwners(systemBus, nameOwners, processName);
31760520631SEd Tanous                 }
31860520631SEd Tanous             }
31960520631SEd Tanous         },
32060520631SEd Tanous         "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
32160520631SEd Tanous         "ListNames");
32260520631SEd Tanous }
32360520631SEd Tanous 
324a82779fbSMatt Spinler // Remove parents of the passed in path that:
325a82779fbSMatt Spinler // 1) Only have the 3 default interfaces on them
326a82779fbSMatt Spinler //    - Means D-Bus created these, not application code,
327a82779fbSMatt Spinler //      with the Properties, Introspectable, and Peer ifaces
328a82779fbSMatt Spinler // 2) Have no other child for this owner
removeUnneededParents(const std::string & objectPath,const std::string & owner,InterfaceMapType & interfaceMap)329a82779fbSMatt Spinler void removeUnneededParents(const std::string& objectPath,
330a82779fbSMatt Spinler                            const std::string& owner,
331a098a37aSBrad Bishop                            InterfaceMapType& interfaceMap)
332a82779fbSMatt Spinler {
333a82779fbSMatt Spinler     auto parent = objectPath;
334a82779fbSMatt Spinler 
335a82779fbSMatt Spinler     while (true)
336a82779fbSMatt Spinler     {
337a82779fbSMatt Spinler         auto pos = parent.find_last_of('/');
338a82779fbSMatt Spinler         if ((pos == std::string::npos) || (pos == 0))
339a82779fbSMatt Spinler         {
340a82779fbSMatt Spinler             break;
341a82779fbSMatt Spinler         }
342a82779fbSMatt Spinler         parent = parent.substr(0, pos);
343a82779fbSMatt Spinler 
344a098a37aSBrad Bishop         auto parentIt = interfaceMap.find(parent);
345a098a37aSBrad Bishop         if (parentIt == interfaceMap.end())
346a82779fbSMatt Spinler         {
347a82779fbSMatt Spinler             break;
348a82779fbSMatt Spinler         }
349a82779fbSMatt Spinler 
350a098a37aSBrad Bishop         auto ifacesIt = parentIt->second.find(owner);
351a098a37aSBrad Bishop         if (ifacesIt == parentIt->second.end())
352a82779fbSMatt Spinler         {
353a82779fbSMatt Spinler             break;
354a82779fbSMatt Spinler         }
355a82779fbSMatt Spinler 
356a098a37aSBrad Bishop         if (ifacesIt->second.size() != 3)
357a82779fbSMatt Spinler         {
358a82779fbSMatt Spinler             break;
359a82779fbSMatt Spinler         }
360a82779fbSMatt Spinler 
361a098a37aSBrad Bishop         auto childPath = parent + '/';
362a82779fbSMatt Spinler 
363a82779fbSMatt Spinler         // Remove this parent if there isn't a remaining child on this owner
3649052ebd3SPatrick Williams         auto child = std::find_if(
3659052ebd3SPatrick Williams             interfaceMap.begin(), interfaceMap.end(),
366a098a37aSBrad Bishop             [&owner, &childPath](const auto& entry) {
36786d2880eSBrad Bishop                 return entry.first.starts_with(childPath) &&
368a82779fbSMatt Spinler                        (entry.second.find(owner) != entry.second.end());
369a82779fbSMatt Spinler             });
370a82779fbSMatt Spinler 
371a098a37aSBrad Bishop         if (child == interfaceMap.end())
372a82779fbSMatt Spinler         {
373a098a37aSBrad Bishop             parentIt->second.erase(ifacesIt);
374a098a37aSBrad Bishop             if (parentIt->second.empty())
375a82779fbSMatt Spinler             {
376a098a37aSBrad Bishop                 interfaceMap.erase(parentIt);
377a82779fbSMatt Spinler             }
378a82779fbSMatt Spinler         }
379a82779fbSMatt Spinler         else
380a82779fbSMatt Spinler         {
381a82779fbSMatt Spinler             break;
382a82779fbSMatt Spinler         }
383a82779fbSMatt Spinler     }
384a82779fbSMatt Spinler }
385a82779fbSMatt Spinler 
main()3861e94e60bSBrad Bishop int main()
38760520631SEd Tanous {
38821c60595SEd Tanous     boost::asio::io_context io;
389a098a37aSBrad Bishop     std::shared_ptr<sdbusplus::asio::connection> systemBus =
39060520631SEd Tanous         std::make_shared<sdbusplus::asio::connection>(io);
39160520631SEd Tanous 
392a098a37aSBrad Bishop     sdbusplus::asio::object_server server(systemBus);
39360520631SEd Tanous 
39460520631SEd Tanous     // Construct a signal set registered for process termination.
39560520631SEd Tanous     boost::asio::signal_set signals(io, SIGINT, SIGTERM);
3969052ebd3SPatrick Williams     signals.async_wait([&io](const boost::system::error_code&, int) {
3979052ebd3SPatrick Williams         io.stop();
3989052ebd3SPatrick Williams     });
39960520631SEd Tanous 
400a098a37aSBrad Bishop     InterfaceMapType interfaceMap;
401a098a37aSBrad Bishop     boost::container::flat_map<std::string, std::string> nameOwners;
40260520631SEd Tanous 
40360ffc244SWilliam A. Kennington III     auto nameChangeHandler = [&interfaceMap, &io, &nameOwners, &server,
404cc8070baSPatrick Williams                               systemBus](sdbusplus::message_t& message) {
4052067926aSAndrew Geissler         std::string name;     // well-known
406a098a37aSBrad Bishop         std::string oldOwner; // unique-name
407a098a37aSBrad Bishop         std::string newOwner; // unique-name
40860520631SEd Tanous 
409a098a37aSBrad Bishop         message.read(name, oldOwner, newOwner);
41060520631SEd Tanous 
41148248203SPatrick Williams         if (name.starts_with(':'))
41248248203SPatrick Williams         {
41348248203SPatrick Williams             // We should do nothing with unique-name connections.
41448248203SPatrick Williams             return;
41548248203SPatrick Williams         }
41648248203SPatrick Williams 
417a098a37aSBrad Bishop         if (!oldOwner.empty())
41860520631SEd Tanous         {
4195b4357daSKallas, Pawel             processNameChangeDelete(io, nameOwners, name, oldOwner,
420a098a37aSBrad Bishop                                     interfaceMap, associationMaps, server);
42160520631SEd Tanous         }
42260520631SEd Tanous 
423a098a37aSBrad Bishop         if (!newOwner.empty())
42460520631SEd Tanous         {
425d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
42660520631SEd Tanous             auto transaction = std::make_shared<
42760520631SEd Tanous                 std::chrono::time_point<std::chrono::steady_clock>>(
42860520631SEd Tanous                 std::chrono::steady_clock::now());
429aecabe86SMatt Spinler #endif
43060520631SEd Tanous             // New daemon added
4311e94e60bSBrad Bishop             if (needToIntrospect(name))
43260520631SEd Tanous             {
433a098a37aSBrad Bishop                 nameOwners[newOwner] = name;
434a098a37aSBrad Bishop                 startNewIntrospect(systemBus.get(), io, interfaceMap, name,
435a098a37aSBrad Bishop                                    associationMaps,
436d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
437aecabe86SMatt Spinler                                    transaction,
438aecabe86SMatt Spinler #endif
439aecabe86SMatt Spinler                                    server);
44060520631SEd Tanous             }
44160520631SEd Tanous         }
44260520631SEd Tanous     };
44360520631SEd Tanous 
444cc8070baSPatrick Williams     sdbusplus::bus::match_t nameOwnerChanged(
445cc8070baSPatrick Williams         static_cast<sdbusplus::bus_t&>(*systemBus),
44660ffc244SWilliam A. Kennington III         sdbusplus::bus::match::rules::nameOwnerChanged(),
44760ffc244SWilliam A. Kennington III         std::move(nameChangeHandler));
44860520631SEd Tanous 
44960ffc244SWilliam A. Kennington III     auto interfacesAddedHandler = [&io, &interfaceMap, &nameOwners,
4505b4357daSKallas, Pawel                                    &server](sdbusplus::message_t& message) {
451a098a37aSBrad Bishop         sdbusplus::message::object_path objPath;
452a098a37aSBrad Bishop         InterfacesAdded interfacesAdded;
453a098a37aSBrad Bishop         message.read(objPath, interfacesAdded);
454a098a37aSBrad Bishop         std::string wellKnown;
455a098a37aSBrad Bishop         if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
45660520631SEd Tanous         {
45760520631SEd Tanous             return; // only introspect well-known
45860520631SEd Tanous         }
4591e94e60bSBrad Bishop         if (needToIntrospect(wellKnown))
46060520631SEd Tanous         {
46160ffc244SWilliam A. Kennington III             processInterfaceAdded(io, interfaceMap, objPath, interfacesAdded,
46260ffc244SWilliam A. Kennington III                                   wellKnown, associationMaps, server);
46360520631SEd Tanous         }
46460520631SEd Tanous     };
46560520631SEd Tanous 
466cc8070baSPatrick Williams     sdbusplus::bus::match_t interfacesAdded(
467cc8070baSPatrick Williams         static_cast<sdbusplus::bus_t&>(*systemBus),
46860520631SEd Tanous         sdbusplus::bus::match::rules::interfacesAdded(),
46960ffc244SWilliam A. Kennington III         std::move(interfacesAddedHandler));
47060520631SEd Tanous 
47160ffc244SWilliam A. Kennington III     auto interfacesRemovedHandler = [&io, &interfaceMap, &nameOwners,
472cc8070baSPatrick Williams                                      &server](sdbusplus::message_t& message) {
473a098a37aSBrad Bishop         sdbusplus::message::object_path objPath;
474a098a37aSBrad Bishop         std::vector<std::string> interfacesRemoved;
475a098a37aSBrad Bishop         message.read(objPath, interfacesRemoved);
476a098a37aSBrad Bishop         auto connectionMap = interfaceMap.find(objPath.str);
477a098a37aSBrad Bishop         if (connectionMap == interfaceMap.end())
47860520631SEd Tanous         {
47960520631SEd Tanous             return;
48060520631SEd Tanous         }
48160520631SEd Tanous 
48260520631SEd Tanous         std::string sender;
483a098a37aSBrad Bishop         if (!getWellKnown(nameOwners, message.get_sender(), sender))
48460520631SEd Tanous         {
48560520631SEd Tanous             return;
48660520631SEd Tanous         }
487a098a37aSBrad Bishop         for (const std::string& interface : interfacesRemoved)
48860520631SEd Tanous         {
489a098a37aSBrad Bishop             auto interfaceSet = connectionMap->second.find(sender);
490a098a37aSBrad Bishop             if (interfaceSet == connectionMap->second.end())
49160520631SEd Tanous             {
49260520631SEd Tanous                 continue;
49360520631SEd Tanous             }
49460520631SEd Tanous 
495d0cf9428SJohn Wang             if (interface == assocDefsInterface)
49660520631SEd Tanous             {
4975b4357daSKallas, Pawel                 removeAssociation(io, objPath.str, sender, server,
498e2359fb7SMatt Spinler                                   associationMaps);
49960520631SEd Tanous             }
50060520631SEd Tanous 
501a098a37aSBrad Bishop             interfaceSet->second.erase(interface);
5029c3d2859SMatt Spinler 
503a098a37aSBrad Bishop             if (interfaceSet->second.empty())
50460520631SEd Tanous             {
5059c3d2859SMatt Spinler                 // If this was the last interface on this connection,
5069c3d2859SMatt Spinler                 // erase the connection
507a098a37aSBrad Bishop                 connectionMap->second.erase(interfaceSet);
5089c3d2859SMatt Spinler 
5099c3d2859SMatt Spinler                 // Instead of checking if every single path is the endpoint
5109c3d2859SMatt Spinler                 // of an association that needs to be moved to pending,
5119c3d2859SMatt Spinler                 // only check when the only remaining owner of this path is
5129c3d2859SMatt Spinler                 // ourself, which would be because we still own the
5139c3d2859SMatt Spinler                 // association path.
514a098a37aSBrad Bishop                 if ((connectionMap->second.size() == 1) &&
515a098a37aSBrad Bishop                     (connectionMap->second.begin()->first ==
516a02cd54cSBrad Bishop                      "xyz.openbmc_project.ObjectMapper"))
5179c3d2859SMatt Spinler                 {
5189c3d2859SMatt Spinler                     // Remove the 2 association D-Bus paths and move the
5199c3d2859SMatt Spinler                     // association to pending.
52060ffc244SWilliam A. Kennington III                     moveAssociationToPending(io, objPath.str, associationMaps,
52160ffc244SWilliam A. Kennington III                                              server);
5229c3d2859SMatt Spinler                 }
52360520631SEd Tanous             }
52460520631SEd Tanous         }
52560520631SEd Tanous         // If this was the last connection on this object path,
52660520631SEd Tanous         // erase the object path
527a098a37aSBrad Bishop         if (connectionMap->second.empty())
52860520631SEd Tanous         {
529a098a37aSBrad Bishop             interfaceMap.erase(connectionMap);
53060520631SEd Tanous         }
531a82779fbSMatt Spinler 
532a098a37aSBrad Bishop         removeUnneededParents(objPath.str, sender, interfaceMap);
53360520631SEd Tanous     };
53460520631SEd Tanous 
535cc8070baSPatrick Williams     sdbusplus::bus::match_t interfacesRemoved(
536cc8070baSPatrick Williams         static_cast<sdbusplus::bus_t&>(*systemBus),
53760520631SEd Tanous         sdbusplus::bus::match::rules::interfacesRemoved(),
53860ffc244SWilliam A. Kennington III         std::move(interfacesRemovedHandler));
53960520631SEd Tanous 
54060ffc244SWilliam A. Kennington III     auto associationChangedHandler = [&io, &server, &nameOwners, &interfaceMap](
541cc8070baSPatrick Williams                                          sdbusplus::message_t& message) {
54260520631SEd Tanous         std::string objectName;
5432bb2d6baSPatrick Williams         boost::container::flat_map<std::string,
5442bb2d6baSPatrick Williams                                    std::variant<std::vector<Association>>>
54560520631SEd Tanous             values;
54660520631SEd Tanous         message.read(objectName, values);
547d0cf9428SJohn Wang         auto prop = values.find(assocDefsProperty);
5488f876a5aSMatt Spinler         if (prop != values.end())
54960520631SEd Tanous         {
55060520631SEd Tanous             std::vector<Association> associations =
551b05bc12cSPatrick Williams                 std::get<std::vector<Association>>(prop->second);
552937a232eSMatt Spinler 
553a098a37aSBrad Bishop             std::string wellKnown;
554a098a37aSBrad Bishop             if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
555937a232eSMatt Spinler             {
556937a232eSMatt Spinler                 return;
557937a232eSMatt Spinler             }
5585b4357daSKallas, Pawel             associationChanged(io, server, associations, message.get_path(),
559a098a37aSBrad Bishop                                wellKnown, interfaceMap, associationMaps);
56060520631SEd Tanous         }
56160520631SEd Tanous     };
562cc8070baSPatrick Williams     sdbusplus::bus::match_t assocChangedMatch(
563cc8070baSPatrick Williams         static_cast<sdbusplus::bus_t&>(*systemBus),
56460520631SEd Tanous         sdbusplus::bus::match::rules::interface(
56560520631SEd Tanous             "org.freedesktop.DBus.Properties") +
56660520631SEd Tanous             sdbusplus::bus::match::rules::member("PropertiesChanged") +
5678f876a5aSMatt Spinler             sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
56860ffc244SWilliam A. Kennington III         std::move(associationChangedHandler));
5698f876a5aSMatt Spinler 
57060520631SEd Tanous     std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
571a02cd54cSBrad Bishop         server.add_interface("/xyz/openbmc_project/object_mapper",
572a02cd54cSBrad Bishop                              "xyz.openbmc_project.ObjectMapper");
57360520631SEd Tanous 
57460520631SEd Tanous     iface->register_method(
575a098a37aSBrad Bishop         "GetAncestors", [&interfaceMap](std::string& reqPath,
57660520631SEd Tanous                                         std::vector<std::string>& interfaces) {
577a098a37aSBrad Bishop             return getAncestors(interfaceMap, reqPath, interfaces);
57860520631SEd Tanous         });
57960520631SEd Tanous 
58060520631SEd Tanous     iface->register_method(
581a098a37aSBrad Bishop         "GetObject", [&interfaceMap](const std::string& path,
58260520631SEd Tanous                                      std::vector<std::string>& interfaces) {
583a098a37aSBrad Bishop             return getObject(interfaceMap, path, interfaces);
58460520631SEd Tanous         });
58560520631SEd Tanous 
58660520631SEd Tanous     iface->register_method(
587a098a37aSBrad Bishop         "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
58860520631SEd Tanous                                       std::vector<std::string>& interfaces) {
589a098a37aSBrad Bishop             return getSubTree(interfaceMap, reqPath, depth, interfaces);
59060520631SEd Tanous         });
59160520631SEd Tanous 
59260520631SEd Tanous     iface->register_method(
59360520631SEd Tanous         "GetSubTreePaths",
594a098a37aSBrad Bishop         [&interfaceMap](std::string& reqPath, int32_t depth,
59560520631SEd Tanous                         std::vector<std::string>& interfaces) {
596a098a37aSBrad Bishop             return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
59760520631SEd Tanous         });
59860520631SEd Tanous 
59958881d0bSWilly Tu     iface->register_method(
60058881d0bSWilly Tu         "GetAssociatedSubTree",
60158881d0bSWilly Tu         [&interfaceMap](const sdbusplus::message::object_path& associationPath,
60258881d0bSWilly Tu                         const sdbusplus::message::object_path& reqPath,
60358881d0bSWilly Tu                         int32_t depth, std::vector<std::string>& interfaces) {
60458881d0bSWilly Tu             return getAssociatedSubTree(interfaceMap, associationMaps,
60558881d0bSWilly Tu                                         associationPath, reqPath, depth,
60658881d0bSWilly Tu                                         interfaces);
60758881d0bSWilly Tu         });
60858881d0bSWilly Tu 
60958881d0bSWilly Tu     iface->register_method(
61058881d0bSWilly Tu         "GetAssociatedSubTreePaths",
61158881d0bSWilly Tu         [&interfaceMap](const sdbusplus::message::object_path& associationPath,
61258881d0bSWilly Tu                         const sdbusplus::message::object_path& reqPath,
61358881d0bSWilly Tu                         int32_t depth, std::vector<std::string>& interfaces) {
61458881d0bSWilly Tu             return getAssociatedSubTreePaths(interfaceMap, associationMaps,
61558881d0bSWilly Tu                                              associationPath, reqPath, depth,
61658881d0bSWilly Tu                                              interfaces);
61758881d0bSWilly Tu         });
61858881d0bSWilly Tu 
619c363323eSLakshmi Yadlapati     iface->register_method(
620c363323eSLakshmi Yadlapati         "GetAssociatedSubTreeById",
621c363323eSLakshmi Yadlapati         [&interfaceMap](const std::string& id, const std::string& objectPath,
622c363323eSLakshmi Yadlapati                         std::vector<std::string>& subtreeInterfaces,
623c363323eSLakshmi Yadlapati                         const std::string& association,
624c363323eSLakshmi Yadlapati                         std::vector<std::string>& endpointInterfaces) {
625c363323eSLakshmi Yadlapati             return getAssociatedSubTreeById(interfaceMap, associationMaps, id,
626c363323eSLakshmi Yadlapati                                             objectPath, subtreeInterfaces,
627c363323eSLakshmi Yadlapati                                             association, endpointInterfaces);
628c363323eSLakshmi Yadlapati         });
629c363323eSLakshmi Yadlapati 
630c363323eSLakshmi Yadlapati     iface->register_method(
631c363323eSLakshmi Yadlapati         "GetAssociatedSubTreePathsById",
632c363323eSLakshmi Yadlapati         [&interfaceMap](const std::string& id, const std::string& objectPath,
633c363323eSLakshmi Yadlapati                         std::vector<std::string>& subtreeInterfaces,
634c363323eSLakshmi Yadlapati                         const std::string& association,
635c363323eSLakshmi Yadlapati                         std::vector<std::string>& endpointInterfaces) {
636c363323eSLakshmi Yadlapati             return getAssociatedSubTreePathsById(
637c363323eSLakshmi Yadlapati                 interfaceMap, associationMaps, id, objectPath,
638c363323eSLakshmi Yadlapati                 subtreeInterfaces, association, endpointInterfaces);
639c363323eSLakshmi Yadlapati         });
640c363323eSLakshmi Yadlapati 
64160520631SEd Tanous     iface->initialize();
64260520631SEd Tanous 
643*41ad8380SEd Tanous     boost::asio::post(io, [&]() {
644a098a37aSBrad Bishop         doListNames(io, interfaceMap, systemBus.get(), nameOwners,
64511401e2eSMatt Spinler                     associationMaps, server);
64660520631SEd Tanous     });
64760520631SEd Tanous 
648a098a37aSBrad Bishop     systemBus->request_name("xyz.openbmc_project.ObjectMapper");
64964354ef2SVishwanatha Subbanna 
65060520631SEd Tanous     io.run();
65160520631SEd Tanous }
652