blob: 1e3883fe052cd5431d1aff5c08b3b67c4b0b76d3 [file] [log] [blame]
Andrew Geisslera80a3af2019-02-04 14:01:49 -06001#include "associations.hpp"
Andrew Geissler3b025e62019-02-01 10:33:54 -06002#include "processing.hpp"
Matt Spinlerdd945862018-09-07 12:41:05 -05003#include "src/argument.hpp"
Matt Spinler35396c12019-04-05 11:46:57 -05004#include "types.hpp"
Matt Spinlerdd945862018-09-07 12:41:05 -05005
Ed Tanous60520632018-06-11 17:46:52 -07006#include <tinyxml2.h>
7
Ed Tanous60520632018-06-11 17:46:52 -07008#include <boost/algorithm/string/predicate.hpp>
Ed Tanous21c60592020-08-17 23:43:46 -07009#include <boost/asio/io_context.hpp>
10#include <boost/asio/signal_set.hpp>
Ed Tanous60520632018-06-11 17:46:52 -070011#include <boost/container/flat_map.hpp>
Ed Tanous60520632018-06-11 17:46:52 -070012#include <sdbusplus/asio/connection.hpp>
13#include <sdbusplus/asio/object_server.hpp>
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +030014#include <xyz/openbmc_project/Common/error.hpp>
Ed Tanous60520632018-06-11 17:46:52 -070015
Brad Bishop23520882022-05-26 21:39:53 -040016#include <atomic>
17#include <chrono>
Brad Bishopea119462022-05-31 20:32:04 -040018#include <exception>
Brad Bishop23520882022-05-26 21:39:53 -040019#include <iomanip>
20#include <iostream>
Brandon Kimf6ebfc72022-07-07 12:53:44 -070021#include <string>
22#include <string_view>
Brad Bishop1f623802022-05-31 18:22:10 -040023#include <utility>
Brad Bishop23520882022-05-26 21:39:53 -040024
Matt Spinlere2359fb2019-04-05 14:11:33 -050025AssociationMaps associationMaps;
Matt Spinler937a2322019-01-23 13:54:22 -060026
Brad Bishopf944a452022-05-05 15:06:46 -040027static AllowDenyList serviceAllowList;
Matt Spinlerdd945862018-09-07 12:41:05 -050028
Brad Bishopa098a372022-05-05 15:19:04 -040029void updateOwners(sdbusplus::asio::connection* conn,
30 boost::container::flat_map<std::string, std::string>& owners,
31 const std::string& newObject)
Ed Tanous60520632018-06-11 17:46:52 -070032{
Brad Bishopa098a372022-05-05 15:19:04 -040033 if (boost::starts_with(newObject, ":"))
Ed Tanous60520632018-06-11 17:46:52 -070034 {
35 return;
36 }
37 conn->async_method_call(
Brad Bishopa098a372022-05-05 15:19:04 -040038 [&, newObject](const boost::system::error_code ec,
39 const std::string& nameOwner) {
Ed Tanous60520632018-06-11 17:46:52 -070040 if (ec)
41 {
Brad Bishopa098a372022-05-05 15:19:04 -040042 std::cerr << "Error getting owner of " << newObject << " : "
Ed Tanous60520632018-06-11 17:46:52 -070043 << ec << "\n";
44 return;
45 }
Brad Bishopa098a372022-05-05 15:19:04 -040046 owners[nameOwner] = newObject;
Ed Tanous60520632018-06-11 17:46:52 -070047 },
48 "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
Brad Bishopa098a372022-05-05 15:19:04 -040049 newObject);
Ed Tanous60520632018-06-11 17:46:52 -070050}
51
Brad Bishopa098a372022-05-05 15:19:04 -040052void sendIntrospectionCompleteSignal(sdbusplus::asio::connection* systemBus,
53 const std::string& processName)
Ed Tanous60520632018-06-11 17:46:52 -070054{
55 // TODO(ed) This signal doesn't get exposed properly in the
56 // introspect right now. Find out how to register signals in
57 // sdbusplus
Patrick Williamscc8070b2022-07-22 19:26:55 -050058 sdbusplus::message_t m = systemBus->new_signal(
Brad Bishopa02cd542021-10-12 19:12:42 -040059 "/xyz/openbmc_project/object_mapper",
60 "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
Brad Bishopa098a372022-05-05 15:19:04 -040061 m.append(processName);
Ed Tanous60520632018-06-11 17:46:52 -070062 m.signal_send();
63}
64
65struct InProgressIntrospect
66{
Brad Bishop1f623802022-05-31 18:22:10 -040067 InProgressIntrospect() = delete;
68 InProgressIntrospect(const InProgressIntrospect&) = delete;
69 InProgressIntrospect(InProgressIntrospect&&) = delete;
70 InProgressIntrospect& operator=(const InProgressIntrospect&) = delete;
71 InProgressIntrospect& operator=(InProgressIntrospect&&) = delete;
Ed Tanous60520632018-06-11 17:46:52 -070072 InProgressIntrospect(
Brad Bishopa098a372022-05-05 15:19:04 -040073 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
74 const std::string& processName, AssociationMaps& am
Brad Bishopd6aa5522022-05-31 19:23:48 -040075#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050076 ,
Ed Tanous60520632018-06-11 17:46:52 -070077 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -040078 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -050079#endif
80 ) :
Brad Bishopa098a372022-05-05 15:19:04 -040081 systemBus(systemBus),
82 io(io), processName(processName), assocMaps(am)
Brad Bishopd6aa5522022-05-31 19:23:48 -040083#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050084 ,
Brad Bishop1f623802022-05-31 18:22:10 -040085 globalStartTime(std::move(globalStartTime)),
Brad Bishopa098a372022-05-05 15:19:04 -040086 processStartTime(std::chrono::steady_clock::now())
Matt Spinleraecabe82018-09-19 13:25:42 -050087#endif
Brad Bishop23520882022-05-26 21:39:53 -040088 {}
Ed Tanous60520632018-06-11 17:46:52 -070089 ~InProgressIntrospect()
90 {
Brad Bishopea119462022-05-31 20:32:04 -040091 try
Ed Tanous60520632018-06-11 17:46:52 -070092 {
Brad Bishopea119462022-05-31 20:32:04 -040093 sendIntrospectionCompleteSignal(systemBus, processName);
Brad Bishopd6aa5522022-05-31 19:23:48 -040094#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopea119462022-05-31 20:32:04 -040095 std::chrono::duration<float> diff =
96 std::chrono::steady_clock::now() - processStartTime;
97 std::cout << std::setw(50) << processName << " scan took "
98 << diff.count() << " seconds\n";
99
100 // If we're the last outstanding caller globally, calculate the
101 // time it took
102 if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
103 {
104 diff = std::chrono::steady_clock::now() - *globalStartTime;
105 std::cout << "Total scan took " << diff.count()
106 << " seconds to complete\n";
107 }
Matt Spinleraecabe82018-09-19 13:25:42 -0500108#endif
Brad Bishopea119462022-05-31 20:32:04 -0400109 }
110 catch (const std::exception& e)
111 {
112 std::cerr
113 << "Terminating, unhandled exception while introspecting: "
114 << e.what() << "\n";
115 std::terminate();
116 }
117 catch (...)
118 {
119 std::cerr
120 << "Terminating, unhandled exception while introspecting\n";
121 std::terminate();
122 }
Ed Tanous60520632018-06-11 17:46:52 -0700123 }
Brad Bishopa098a372022-05-05 15:19:04 -0400124 sdbusplus::asio::connection* systemBus;
Ed Tanous21c60592020-08-17 23:43:46 -0700125 boost::asio::io_context& io;
Brad Bishopa098a372022-05-05 15:19:04 -0400126 std::string processName;
Matt Spinler11401e22019-04-08 13:13:25 -0500127 AssociationMaps& assocMaps;
Brad Bishopd6aa5522022-05-31 19:23:48 -0400128#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700129 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400130 globalStartTime;
131 std::chrono::time_point<std::chrono::steady_clock> processStartTime;
Matt Spinleraecabe82018-09-19 13:25:42 -0500132#endif
Ed Tanous60520632018-06-11 17:46:52 -0700133};
134
Brad Bishopa098a372022-05-05 15:19:04 -0400135void doAssociations(sdbusplus::asio::connection* systemBus,
136 InterfaceMapType& interfaceMap,
137 sdbusplus::asio::object_server& objectServer,
138 const std::string& processName, const std::string& path,
139 int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700140{
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100141 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400142 systemBus->async_method_call(
143 [&objectServer, path, processName, &interfaceMap, systemBus,
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100144 timeoutRetries](
Matt Spinler937a2322019-01-23 13:54:22 -0600145 const boost::system::error_code ec,
Patrick Williams2bb2d6b2020-05-13 17:59:02 -0500146 const std::variant<std::vector<Association>>& variantAssociations) {
Ed Tanous60520632018-06-11 17:46:52 -0700147 if (ec)
148 {
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100149 if (ec.value() == boost::system::errc::timed_out &&
150 timeoutRetries < maxTimeoutRetries)
151 {
Brad Bishopa098a372022-05-05 15:19:04 -0400152 doAssociations(systemBus, interfaceMap, objectServer,
153 processName, path, timeoutRetries + 1);
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100154 return;
155 }
Ed Tanous60520632018-06-11 17:46:52 -0700156 std::cerr << "Error getting associations from " << path << "\n";
157 }
158 std::vector<Association> associations =
Patrick Williamsb05bc122020-05-13 12:21:00 -0500159 std::get<std::vector<Association>>(variantAssociations);
Andrew Geissler4511b332019-02-21 15:40:40 -0600160 associationChanged(objectServer, associations, path, processName,
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500161 interfaceMap, associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700162 },
163 processName, path, "org.freedesktop.DBus.Properties", "Get",
John Wangd0cf9422019-09-17 16:01:34 +0800164 assocDefsInterface, assocDefsProperty);
Ed Tanous60520632018-06-11 17:46:52 -0700165}
166
Brad Bishopa098a372022-05-05 15:19:04 -0400167void doIntrospect(sdbusplus::asio::connection* systemBus,
Brad Bishop1f623802022-05-31 18:22:10 -0400168 const std::shared_ptr<InProgressIntrospect>& transaction,
Brad Bishopa098a372022-05-05 15:19:04 -0400169 InterfaceMapType& interfaceMap,
170 sdbusplus::asio::object_server& objectServer,
Brad Bishop1f623802022-05-31 18:22:10 -0400171 const std::string& path, int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700172{
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800173 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400174 systemBus->async_method_call(
175 [&interfaceMap, &objectServer, transaction, path, systemBus,
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800176 timeoutRetries](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400177 const std::string& introspectXml) {
Ed Tanous60520632018-06-11 17:46:52 -0700178 if (ec)
179 {
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800180 if (ec.value() == boost::system::errc::timed_out &&
181 timeoutRetries < maxTimeoutRetries)
182 {
Brad Bishopa098a372022-05-05 15:19:04 -0400183 doIntrospect(systemBus, transaction, interfaceMap,
184 objectServer, path, timeoutRetries + 1);
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800185 return;
186 }
Ed Tanous60520632018-06-11 17:46:52 -0700187 std::cerr << "Introspect call failed with error: " << ec << ", "
188 << ec.message()
Brad Bishopa098a372022-05-05 15:19:04 -0400189 << " on process: " << transaction->processName
Ed Tanous60520632018-06-11 17:46:52 -0700190 << " path: " << path << "\n";
191 return;
192 }
193
194 tinyxml2::XMLDocument doc;
195
Brad Bishopa098a372022-05-05 15:19:04 -0400196 tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
Ed Tanous60520632018-06-11 17:46:52 -0700197 if (e != tinyxml2::XMLError::XML_SUCCESS)
198 {
199 std::cerr << "XML parsing failed\n";
200 return;
201 }
202
203 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
204 if (pRoot == nullptr)
205 {
206 std::cerr << "XML document did not contain any data\n";
207 return;
208 }
Brad Bishopa098a372022-05-05 15:19:04 -0400209 auto& thisPathMap = interfaceMap[path];
Ed Tanous60520632018-06-11 17:46:52 -0700210 tinyxml2::XMLElement* pElement =
211 pRoot->FirstChildElement("interface");
212 while (pElement != nullptr)
213 {
Brad Bishopa098a372022-05-05 15:19:04 -0400214 const char* ifaceName = pElement->Attribute("name");
215 if (ifaceName == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700216 {
217 continue;
218 }
219
Brad Bishopa098a372022-05-05 15:19:04 -0400220 thisPathMap[transaction->processName].emplace(ifaceName);
Ed Tanousd4dd96a2018-11-12 11:37:44 -0800221
Brad Bishopa098a372022-05-05 15:19:04 -0400222 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
Ed Tanous60520632018-06-11 17:46:52 -0700223 {
Brad Bishopa098a372022-05-05 15:19:04 -0400224 doAssociations(systemBus, interfaceMap, objectServer,
225 transaction->processName, path);
Ed Tanous60520632018-06-11 17:46:52 -0700226 }
Ed Tanous60520632018-06-11 17:46:52 -0700227
228 pElement = pElement->NextSiblingElement("interface");
229 }
230
Matt Spinler11401e22019-04-08 13:13:25 -0500231 // Check if this new path has a pending association that can
232 // now be completed.
Brad Bishopa098a372022-05-05 15:19:04 -0400233 checkIfPendingAssociation(path, interfaceMap,
Matt Spinler11401e22019-04-08 13:13:25 -0500234 transaction->assocMaps, objectServer);
235
Ed Tanous50232cd2018-11-12 11:34:43 -0800236 pElement = pRoot->FirstChildElement("node");
237 while (pElement != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700238 {
Brad Bishopa098a372022-05-05 15:19:04 -0400239 const char* childPath = pElement->Attribute("name");
240 if (childPath != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700241 {
Brad Bishopa098a372022-05-05 15:19:04 -0400242 std::string parentPath(path);
243 if (parentPath == "/")
Ed Tanous60520632018-06-11 17:46:52 -0700244 {
Brad Bishopa098a372022-05-05 15:19:04 -0400245 parentPath.clear();
Ed Tanous60520632018-06-11 17:46:52 -0700246 }
Ed Tanous50232cd2018-11-12 11:34:43 -0800247
Brad Bishopa098a372022-05-05 15:19:04 -0400248 doIntrospect(systemBus, transaction, interfaceMap,
249 objectServer, parentPath + "/" + childPath);
Ed Tanous60520632018-06-11 17:46:52 -0700250 }
Ed Tanous50232cd2018-11-12 11:34:43 -0800251 pElement = pElement->NextSiblingElement("node");
Ed Tanous60520632018-06-11 17:46:52 -0700252 }
253 },
Brad Bishopa098a372022-05-05 15:19:04 -0400254 transaction->processName, path, "org.freedesktop.DBus.Introspectable",
Ed Tanous60520632018-06-11 17:46:52 -0700255 "Introspect");
256}
257
Brad Bishopa098a372022-05-05 15:19:04 -0400258void startNewIntrospect(
259 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
260 InterfaceMapType& interfaceMap, const std::string& processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500261 AssociationMaps& assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400262#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700263 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400264 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500265#endif
Ed Tanous60520632018-06-11 17:46:52 -0700266 sdbusplus::asio::object_server& objectServer)
267{
Brad Bishopd5542322022-06-02 19:56:23 -0400268 if (needToIntrospect(processName, serviceAllowList))
Ed Tanous60520632018-06-11 17:46:52 -0700269 {
Ed Tanous60520632018-06-11 17:46:52 -0700270 std::shared_ptr<InProgressIntrospect> transaction =
Brad Bishopa098a372022-05-05 15:19:04 -0400271 std::make_shared<InProgressIntrospect>(systemBus, io, processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500272 assocMaps
Brad Bishopd6aa5522022-05-31 19:23:48 -0400273#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -0500274 ,
Brad Bishopa098a372022-05-05 15:19:04 -0400275 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -0500276#endif
277 );
Ed Tanous60520632018-06-11 17:46:52 -0700278
Brad Bishopa098a372022-05-05 15:19:04 -0400279 doIntrospect(systemBus, transaction, interfaceMap, objectServer, "/");
Ed Tanous60520632018-06-11 17:46:52 -0700280 }
281}
282
283// TODO(ed) replace with std::set_intersection once c++17 is available
284template <class InputIt1, class InputIt2>
285bool intersect(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
286{
287 while (first1 != last1 && first2 != last2)
288 {
289 if (*first1 < *first2)
290 {
291 ++first1;
292 continue;
293 }
294 if (*first2 < *first1)
295 {
296 ++first2;
297 continue;
298 }
299 return true;
300 }
301 return false;
302}
303
304void doListNames(
Brad Bishopa098a372022-05-05 15:19:04 -0400305 boost::asio::io_context& io, InterfaceMapType& interfaceMap,
306 sdbusplus::asio::connection* systemBus,
307 boost::container::flat_map<std::string, std::string>& nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500308 AssociationMaps& assocMaps, sdbusplus::asio::object_server& objectServer)
Ed Tanous60520632018-06-11 17:46:52 -0700309{
Brad Bishopa098a372022-05-05 15:19:04 -0400310 systemBus->async_method_call(
311 [&io, &interfaceMap, &nameOwners, &objectServer, systemBus,
Matt Spinler11401e22019-04-08 13:13:25 -0500312 &assocMaps](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400313 std::vector<std::string> processNames) {
Ed Tanous60520632018-06-11 17:46:52 -0700314 if (ec)
315 {
316 std::cerr << "Error getting names: " << ec << "\n";
317 std::exit(EXIT_FAILURE);
318 return;
319 }
Ed Tanous60520632018-06-11 17:46:52 -0700320 // Try to make startup consistent
Brad Bishopa098a372022-05-05 15:19:04 -0400321 std::sort(processNames.begin(), processNames.end());
Brad Bishopd6aa5522022-05-31 19:23:48 -0400322#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700323 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400324 globalStartTime = std::make_shared<
Ed Tanous60520632018-06-11 17:46:52 -0700325 std::chrono::time_point<std::chrono::steady_clock>>(
326 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500327#endif
Brad Bishopa098a372022-05-05 15:19:04 -0400328 for (const std::string& processName : processNames)
Ed Tanous60520632018-06-11 17:46:52 -0700329 {
Brad Bishopd5542322022-06-02 19:56:23 -0400330 if (needToIntrospect(processName, serviceAllowList))
Ed Tanous60520632018-06-11 17:46:52 -0700331 {
Brad Bishopa098a372022-05-05 15:19:04 -0400332 startNewIntrospect(systemBus, io, interfaceMap, processName,
333 assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400334#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopa098a372022-05-05 15:19:04 -0400335 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500336#endif
Brad Bishopa098a372022-05-05 15:19:04 -0400337 objectServer);
338 updateOwners(systemBus, nameOwners, processName);
Ed Tanous60520632018-06-11 17:46:52 -0700339 }
340 }
341 },
342 "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
343 "ListNames");
344}
345
Matt Spinlerdd945862018-09-07 12:41:05 -0500346void splitArgs(const std::string& stringArgs,
347 boost::container::flat_set<std::string>& listArgs)
348{
349 std::istringstream args;
350 std::string arg;
351
352 args.str(stringArgs);
353
354 while (!args.eof())
355 {
356 args >> arg;
357 if (!arg.empty())
358 {
359 listArgs.insert(arg);
360 }
361 }
362}
363
Ed Tanous964681c2022-07-08 12:47:24 -0700364void addObjectMapResult(std::vector<InterfaceMapType::value_type>& objectMap,
365 const std::string& objectPath,
366 const ConnectionNames::value_type& interfaceMap)
Matt Spinler9f0958e2018-09-11 08:26:10 -0500367{
368 // Adds an object path/service name/interface list entry to
Matt Spinler47c09752018-11-29 14:54:13 -0600369 // the results of GetSubTree and GetAncestors.
Matt Spinler9f0958e2018-09-11 08:26:10 -0500370 // If an entry for the object path already exists, just add the
371 // service name and interfaces to that entry, otherwise create
372 // a new entry.
373 auto entry = std::find_if(
Matt Spinler47c09752018-11-29 14:54:13 -0600374 objectMap.begin(), objectMap.end(),
Matt Spinler9f0958e2018-09-11 08:26:10 -0500375 [&objectPath](const auto& i) { return objectPath == i.first; });
376
Matt Spinler47c09752018-11-29 14:54:13 -0600377 if (entry != objectMap.end())
Matt Spinler9f0958e2018-09-11 08:26:10 -0500378 {
379 entry->second.emplace(interfaceMap);
380 }
381 else
382 {
Brad Bishopa098a372022-05-05 15:19:04 -0400383 InterfaceMapType::value_type object;
Matt Spinler9f0958e2018-09-11 08:26:10 -0500384 object.first = objectPath;
385 object.second.emplace(interfaceMap);
Matt Spinler47c09752018-11-29 14:54:13 -0600386 objectMap.push_back(object);
Matt Spinler9f0958e2018-09-11 08:26:10 -0500387 }
388}
389
Matt Spinlera82779f2019-01-09 12:39:42 -0600390// Remove parents of the passed in path that:
391// 1) Only have the 3 default interfaces on them
392// - Means D-Bus created these, not application code,
393// with the Properties, Introspectable, and Peer ifaces
394// 2) Have no other child for this owner
395void removeUnneededParents(const std::string& objectPath,
396 const std::string& owner,
Brad Bishopa098a372022-05-05 15:19:04 -0400397 InterfaceMapType& interfaceMap)
Matt Spinlera82779f2019-01-09 12:39:42 -0600398{
399 auto parent = objectPath;
400
401 while (true)
402 {
403 auto pos = parent.find_last_of('/');
404 if ((pos == std::string::npos) || (pos == 0))
405 {
406 break;
407 }
408 parent = parent.substr(0, pos);
409
Brad Bishopa098a372022-05-05 15:19:04 -0400410 auto parentIt = interfaceMap.find(parent);
411 if (parentIt == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600412 {
413 break;
414 }
415
Brad Bishopa098a372022-05-05 15:19:04 -0400416 auto ifacesIt = parentIt->second.find(owner);
417 if (ifacesIt == parentIt->second.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600418 {
419 break;
420 }
421
Brad Bishopa098a372022-05-05 15:19:04 -0400422 if (ifacesIt->second.size() != 3)
Matt Spinlera82779f2019-01-09 12:39:42 -0600423 {
424 break;
425 }
426
Brad Bishopa098a372022-05-05 15:19:04 -0400427 auto childPath = parent + '/';
Matt Spinlera82779f2019-01-09 12:39:42 -0600428
429 // Remove this parent if there isn't a remaining child on this owner
430 auto child = std::find_if(
Brad Bishopa098a372022-05-05 15:19:04 -0400431 interfaceMap.begin(), interfaceMap.end(),
432 [&owner, &childPath](const auto& entry) {
433 return boost::starts_with(entry.first, childPath) &&
Matt Spinlera82779f2019-01-09 12:39:42 -0600434 (entry.second.find(owner) != entry.second.end());
435 });
436
Brad Bishopa098a372022-05-05 15:19:04 -0400437 if (child == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600438 {
Brad Bishopa098a372022-05-05 15:19:04 -0400439 parentIt->second.erase(ifacesIt);
440 if (parentIt->second.empty())
Matt Spinlera82779f2019-01-09 12:39:42 -0600441 {
Brad Bishopa098a372022-05-05 15:19:04 -0400442 interfaceMap.erase(parentIt);
Matt Spinlera82779f2019-01-09 12:39:42 -0600443 }
444 }
445 else
446 {
447 break;
448 }
449 }
450}
451
Brad Bishopa098a372022-05-05 15:19:04 -0400452std::vector<InterfaceMapType::value_type>
453 getAncestors(const InterfaceMapType& interfaceMap, std::string reqPath,
Ed Tanous0a13c762021-09-28 13:29:25 -0700454 std::vector<std::string>& interfaces)
455{
456 // Interfaces need to be sorted for intersect to function
457 std::sort(interfaces.begin(), interfaces.end());
458
Brad Bishopa098a372022-05-05 15:19:04 -0400459 if (boost::ends_with(reqPath, "/"))
Ed Tanous0a13c762021-09-28 13:29:25 -0700460 {
Brad Bishopa098a372022-05-05 15:19:04 -0400461 reqPath.pop_back();
Ed Tanous0a13c762021-09-28 13:29:25 -0700462 }
Brad Bishop1f623802022-05-31 18:22:10 -0400463 if (!reqPath.empty() && interfaceMap.find(reqPath) == interfaceMap.end())
Ed Tanous0a13c762021-09-28 13:29:25 -0700464 {
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +0300465 throw sdbusplus::xyz::openbmc_project::Common::Error::
466 ResourceNotFound();
Ed Tanous0a13c762021-09-28 13:29:25 -0700467 }
468
Brad Bishopa098a372022-05-05 15:19:04 -0400469 std::vector<InterfaceMapType::value_type> ret;
Brad Bishop1f623802022-05-31 18:22:10 -0400470 for (const auto& objectPath : interfaceMap)
Ed Tanous0a13c762021-09-28 13:29:25 -0700471 {
Brad Bishop1f623802022-05-31 18:22:10 -0400472 const auto& thisPath = objectPath.first;
Brandon Kim82720f02022-07-08 09:57:22 -0700473
474 if (reqPath == thisPath)
475 {
476 continue;
477 }
478
479 if (boost::starts_with(reqPath, thisPath))
Ed Tanous0a13c762021-09-28 13:29:25 -0700480 {
481 if (interfaces.empty())
482 {
Brad Bishopa098a372022-05-05 15:19:04 -0400483 ret.emplace_back(objectPath);
Ed Tanous0a13c762021-09-28 13:29:25 -0700484 }
485 else
486 {
Brad Bishop1f623802022-05-31 18:22:10 -0400487 for (const auto& interfaceMap : objectPath.second)
Ed Tanous0a13c762021-09-28 13:29:25 -0700488 {
Ed Tanous0a13c762021-09-28 13:29:25 -0700489 if (intersect(interfaces.begin(), interfaces.end(),
Brad Bishopa098a372022-05-05 15:19:04 -0400490 interfaceMap.second.begin(),
491 interfaceMap.second.end()))
Ed Tanous0a13c762021-09-28 13:29:25 -0700492 {
Brad Bishopa098a372022-05-05 15:19:04 -0400493 addObjectMapResult(ret, thisPath, interfaceMap);
Ed Tanous0a13c762021-09-28 13:29:25 -0700494 }
495 }
496 }
497 }
498 }
499
500 return ret;
501}
502
Ed Tanous964681c2022-07-08 12:47:24 -0700503ConnectionNames getObject(const InterfaceMapType& interfaceMap,
504 const std::string& path,
505 std::vector<std::string>& interfaces)
Ed Tanous0a13c762021-09-28 13:29:25 -0700506{
Ed Tanous964681c2022-07-08 12:47:24 -0700507 ConnectionNames results;
Ed Tanous0a13c762021-09-28 13:29:25 -0700508
509 // Interfaces need to be sorted for intersect to function
510 std::sort(interfaces.begin(), interfaces.end());
Brad Bishopa098a372022-05-05 15:19:04 -0400511 auto pathRef = interfaceMap.find(path);
512 if (pathRef == interfaceMap.end())
Ed Tanous0a13c762021-09-28 13:29:25 -0700513 {
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +0300514 throw sdbusplus::xyz::openbmc_project::Common::Error::
515 ResourceNotFound();
Ed Tanous0a13c762021-09-28 13:29:25 -0700516 }
517 if (interfaces.empty())
518 {
Brad Bishopa098a372022-05-05 15:19:04 -0400519 return pathRef->second;
Ed Tanous0a13c762021-09-28 13:29:25 -0700520 }
Brad Bishop1f623802022-05-31 18:22:10 -0400521 for (const auto& interfaceMap : pathRef->second)
Ed Tanous0a13c762021-09-28 13:29:25 -0700522 {
523 if (intersect(interfaces.begin(), interfaces.end(),
Brad Bishopa098a372022-05-05 15:19:04 -0400524 interfaceMap.second.begin(), interfaceMap.second.end()))
Ed Tanous0a13c762021-09-28 13:29:25 -0700525 {
Brad Bishopa098a372022-05-05 15:19:04 -0400526 results.emplace(interfaceMap.first, interfaceMap.second);
Ed Tanous0a13c762021-09-28 13:29:25 -0700527 }
528 }
529
530 if (results.empty())
531 {
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +0300532 throw sdbusplus::xyz::openbmc_project::Common::Error::
533 ResourceNotFound();
Ed Tanous0a13c762021-09-28 13:29:25 -0700534 }
535
536 return results;
537}
538
Brad Bishopa098a372022-05-05 15:19:04 -0400539std::vector<InterfaceMapType::value_type>
540 getSubTree(const InterfaceMapType& interfaceMap, std::string reqPath,
Ed Tanous0a13c762021-09-28 13:29:25 -0700541 int32_t depth, std::vector<std::string>& interfaces)
542{
543 if (depth <= 0)
544 {
545 depth = std::numeric_limits<int32_t>::max();
546 }
547 // Interfaces need to be sorted for intersect to function
548 std::sort(interfaces.begin(), interfaces.end());
Ed Tanous0a13c762021-09-28 13:29:25 -0700549
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700550 // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
551 // will be guaranteed not to have a trailing "/"
552 if (!boost::ends_with(reqPath, "/"))
Ed Tanous0a13c762021-09-28 13:29:25 -0700553 {
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700554 reqPath += "/";
Ed Tanous0a13c762021-09-28 13:29:25 -0700555 }
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700556 std::string_view reqPathStripped =
557 std::string_view(reqPath).substr(0, reqPath.size() - 1);
558
559 if (!reqPathStripped.empty() &&
560 interfaceMap.find(reqPathStripped) == interfaceMap.end())
Ed Tanous0a13c762021-09-28 13:29:25 -0700561 {
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +0300562 throw sdbusplus::xyz::openbmc_project::Common::Error::
563 ResourceNotFound();
Ed Tanous0a13c762021-09-28 13:29:25 -0700564 }
565
Brandon Kim82720f02022-07-08 09:57:22 -0700566 std::vector<InterfaceMapType::value_type> ret;
Brad Bishop1f623802022-05-31 18:22:10 -0400567 for (const auto& objectPath : interfaceMap)
Ed Tanous0a13c762021-09-28 13:29:25 -0700568 {
Brad Bishop1f623802022-05-31 18:22:10 -0400569 const auto& thisPath = objectPath.first;
Ed Tanous0a13c762021-09-28 13:29:25 -0700570
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700571 // Skip exact match on stripped search term
572 if (thisPath == reqPathStripped)
Ed Tanous0a13c762021-09-28 13:29:25 -0700573 {
574 continue;
575 }
576
Brad Bishopa098a372022-05-05 15:19:04 -0400577 if (boost::starts_with(thisPath, reqPath))
Ed Tanous0a13c762021-09-28 13:29:25 -0700578 {
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700579 // count the number of slashes past the stripped search term
580 int32_t thisDepth = std::count(
581 thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
Brad Bishopa098a372022-05-05 15:19:04 -0400582 if (thisDepth <= depth)
Ed Tanous0a13c762021-09-28 13:29:25 -0700583 {
Brad Bishop1f623802022-05-31 18:22:10 -0400584 for (const auto& interfaceMap : objectPath.second)
Ed Tanous0a13c762021-09-28 13:29:25 -0700585 {
586 if (intersect(interfaces.begin(), interfaces.end(),
Brad Bishopa098a372022-05-05 15:19:04 -0400587 interfaceMap.second.begin(),
588 interfaceMap.second.end()) ||
Ed Tanous0a13c762021-09-28 13:29:25 -0700589 interfaces.empty())
590 {
Brad Bishopa098a372022-05-05 15:19:04 -0400591 addObjectMapResult(ret, thisPath, interfaceMap);
Ed Tanous0a13c762021-09-28 13:29:25 -0700592 }
593 }
594 }
595 }
596 }
597
598 return ret;
599}
600
Brad Bishopa098a372022-05-05 15:19:04 -0400601std::vector<std::string> getSubTreePaths(const InterfaceMapType& interfaceMap,
602 std::string reqPath, int32_t depth,
603 std::vector<std::string>& interfaces)
Ed Tanous0a13c762021-09-28 13:29:25 -0700604{
605 if (depth <= 0)
606 {
607 depth = std::numeric_limits<int32_t>::max();
608 }
609 // Interfaces need to be sorted for intersect to function
610 std::sort(interfaces.begin(), interfaces.end());
Ed Tanous0a13c762021-09-28 13:29:25 -0700611
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700612 // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
613 // will be guaranteed not to have a trailing "/"
614 if (!boost::ends_with(reqPath, "/"))
Ed Tanous0a13c762021-09-28 13:29:25 -0700615 {
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700616 reqPath += "/";
Ed Tanous0a13c762021-09-28 13:29:25 -0700617 }
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700618 std::string_view reqPathStripped =
619 std::string_view(reqPath).substr(0, reqPath.size() - 1);
620
621 if (!reqPathStripped.empty() &&
622 interfaceMap.find(reqPathStripped) == interfaceMap.end())
Ed Tanous0a13c762021-09-28 13:29:25 -0700623 {
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +0300624 throw sdbusplus::xyz::openbmc_project::Common::Error::
625 ResourceNotFound();
Ed Tanous0a13c762021-09-28 13:29:25 -0700626 }
627
Brandon Kim82720f02022-07-08 09:57:22 -0700628 std::vector<std::string> ret;
Brad Bishop1f623802022-05-31 18:22:10 -0400629 for (const auto& objectPath : interfaceMap)
Ed Tanous0a13c762021-09-28 13:29:25 -0700630 {
Brad Bishop1f623802022-05-31 18:22:10 -0400631 const auto& thisPath = objectPath.first;
Ed Tanous0a13c762021-09-28 13:29:25 -0700632
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700633 // Skip exact match on stripped search term
634 if (thisPath == reqPathStripped)
Ed Tanous0a13c762021-09-28 13:29:25 -0700635 {
636 continue;
637 }
638
Brad Bishopa098a372022-05-05 15:19:04 -0400639 if (boost::starts_with(thisPath, reqPath))
Ed Tanous0a13c762021-09-28 13:29:25 -0700640 {
Brandon Kimf6ebfc72022-07-07 12:53:44 -0700641 // count the number of slashes past the stripped search term
642 int thisDepth = std::count(
643 thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
Brad Bishopa098a372022-05-05 15:19:04 -0400644 if (thisDepth <= depth)
Ed Tanous0a13c762021-09-28 13:29:25 -0700645 {
646 bool add = interfaces.empty();
Brad Bishop1f623802022-05-31 18:22:10 -0400647 for (const auto& interfaceMap : objectPath.second)
Ed Tanous0a13c762021-09-28 13:29:25 -0700648 {
649 if (intersect(interfaces.begin(), interfaces.end(),
Brad Bishopa098a372022-05-05 15:19:04 -0400650 interfaceMap.second.begin(),
651 interfaceMap.second.end()))
Ed Tanous0a13c762021-09-28 13:29:25 -0700652 {
653 add = true;
654 break;
655 }
656 }
657 if (add)
658 {
659 // TODO(ed) this is a copy
Brad Bishopa098a372022-05-05 15:19:04 -0400660 ret.emplace_back(thisPath);
Ed Tanous0a13c762021-09-28 13:29:25 -0700661 }
662 }
663 }
664 }
665
666 return ret;
667}
668
Ed Tanous60520632018-06-11 17:46:52 -0700669int main(int argc, char** argv)
670{
Matt Spinlerdd945862018-09-07 12:41:05 -0500671 auto options = ArgumentParser(argc, argv);
Ed Tanous21c60592020-08-17 23:43:46 -0700672 boost::asio::io_context io;
Brad Bishopa098a372022-05-05 15:19:04 -0400673 std::shared_ptr<sdbusplus::asio::connection> systemBus =
Ed Tanous60520632018-06-11 17:46:52 -0700674 std::make_shared<sdbusplus::asio::connection>(io);
675
Brad Bishopf944a452022-05-05 15:06:46 -0400676 splitArgs(options["service-namespaces"], serviceAllowList);
Matt Spinlerdd945862018-09-07 12:41:05 -0500677
Brad Bishopa098a372022-05-05 15:19:04 -0400678 sdbusplus::asio::object_server server(systemBus);
Ed Tanous60520632018-06-11 17:46:52 -0700679
680 // Construct a signal set registered for process termination.
681 boost::asio::signal_set signals(io, SIGINT, SIGTERM);
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400682 signals.async_wait(
683 [&io](const boost::system::error_code&, int) { io.stop(); });
Ed Tanous60520632018-06-11 17:46:52 -0700684
Brad Bishopa098a372022-05-05 15:19:04 -0400685 InterfaceMapType interfaceMap;
686 boost::container::flat_map<std::string, std::string> nameOwners;
Ed Tanous60520632018-06-11 17:46:52 -0700687
Patrick Williamscc8070b2022-07-22 19:26:55 -0500688 std::function<void(sdbusplus::message_t & message)> nameChangeHandler =
689 [&interfaceMap, &io, &nameOwners, &server,
690 systemBus](sdbusplus::message_t& message) {
Brad Bishopa098a372022-05-05 15:19:04 -0400691 std::string name; // well-known
692 std::string oldOwner; // unique-name
693 std::string newOwner; // unique-name
Ed Tanous60520632018-06-11 17:46:52 -0700694
Brad Bishopa098a372022-05-05 15:19:04 -0400695 message.read(name, oldOwner, newOwner);
Ed Tanous60520632018-06-11 17:46:52 -0700696
Brad Bishopa098a372022-05-05 15:19:04 -0400697 if (!oldOwner.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700698 {
Brad Bishopa098a372022-05-05 15:19:04 -0400699 processNameChangeDelete(nameOwners, name, oldOwner,
700 interfaceMap, associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700701 }
702
Brad Bishopa098a372022-05-05 15:19:04 -0400703 if (!newOwner.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700704 {
Brad Bishopd6aa5522022-05-31 19:23:48 -0400705#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700706 auto transaction = std::make_shared<
707 std::chrono::time_point<std::chrono::steady_clock>>(
708 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500709#endif
Ed Tanous60520632018-06-11 17:46:52 -0700710 // New daemon added
Brad Bishopd5542322022-06-02 19:56:23 -0400711 if (needToIntrospect(name, serviceAllowList))
Ed Tanous60520632018-06-11 17:46:52 -0700712 {
Brad Bishopa098a372022-05-05 15:19:04 -0400713 nameOwners[newOwner] = name;
714 startNewIntrospect(systemBus.get(), io, interfaceMap, name,
715 associationMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400716#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopa098a372022-05-05 15:19:04 -0400717 transaction,
Matt Spinleraecabe82018-09-19 13:25:42 -0500718#endif
Brad Bishopa098a372022-05-05 15:19:04 -0400719 server);
Ed Tanous60520632018-06-11 17:46:52 -0700720 }
721 }
722 };
723
Patrick Williamscc8070b2022-07-22 19:26:55 -0500724 sdbusplus::bus::match_t nameOwnerChanged(
725 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700726 sdbusplus::bus::match::rules::nameOwnerChanged(), nameChangeHandler);
727
Patrick Williamscc8070b2022-07-22 19:26:55 -0500728 std::function<void(sdbusplus::message_t & message)> interfacesAddedHandler =
729 [&interfaceMap, &nameOwners, &server](sdbusplus::message_t& message) {
Brad Bishopa098a372022-05-05 15:19:04 -0400730 sdbusplus::message::object_path objPath;
731 InterfacesAdded interfacesAdded;
732 message.read(objPath, interfacesAdded);
733 std::string wellKnown;
734 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
Ed Tanous60520632018-06-11 17:46:52 -0700735 {
736 return; // only introspect well-known
737 }
Brad Bishopd5542322022-06-02 19:56:23 -0400738 if (needToIntrospect(wellKnown, serviceAllowList))
Ed Tanous60520632018-06-11 17:46:52 -0700739 {
Brad Bishopa098a372022-05-05 15:19:04 -0400740 processInterfaceAdded(interfaceMap, objPath, interfacesAdded,
741 wellKnown, associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700742 }
743 };
744
Patrick Williamscc8070b2022-07-22 19:26:55 -0500745 sdbusplus::bus::match_t interfacesAdded(
746 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700747 sdbusplus::bus::match::rules::interfacesAdded(),
748 interfacesAddedHandler);
749
Patrick Williamscc8070b2022-07-22 19:26:55 -0500750 std::function<void(sdbusplus::message_t & message)>
751 interfacesRemovedHandler = [&interfaceMap, &nameOwners,
752 &server](sdbusplus::message_t& message) {
Brad Bishopa098a372022-05-05 15:19:04 -0400753 sdbusplus::message::object_path objPath;
754 std::vector<std::string> interfacesRemoved;
755 message.read(objPath, interfacesRemoved);
756 auto connectionMap = interfaceMap.find(objPath.str);
757 if (connectionMap == interfaceMap.end())
Ed Tanous60520632018-06-11 17:46:52 -0700758 {
759 return;
760 }
761
762 std::string sender;
Brad Bishopa098a372022-05-05 15:19:04 -0400763 if (!getWellKnown(nameOwners, message.get_sender(), sender))
Ed Tanous60520632018-06-11 17:46:52 -0700764 {
765 return;
766 }
Brad Bishopa098a372022-05-05 15:19:04 -0400767 for (const std::string& interface : interfacesRemoved)
Ed Tanous60520632018-06-11 17:46:52 -0700768 {
Brad Bishopa098a372022-05-05 15:19:04 -0400769 auto interfaceSet = connectionMap->second.find(sender);
770 if (interfaceSet == connectionMap->second.end())
Ed Tanous60520632018-06-11 17:46:52 -0700771 {
772 continue;
773 }
774
John Wangd0cf9422019-09-17 16:01:34 +0800775 if (interface == assocDefsInterface)
Ed Tanous60520632018-06-11 17:46:52 -0700776 {
Brad Bishopa098a372022-05-05 15:19:04 -0400777 removeAssociation(objPath.str, sender, server,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500778 associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700779 }
780
Brad Bishopa098a372022-05-05 15:19:04 -0400781 interfaceSet->second.erase(interface);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500782
Brad Bishopa098a372022-05-05 15:19:04 -0400783 if (interfaceSet->second.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700784 {
Matt Spinler9c3d2852019-04-08 15:57:19 -0500785 // If this was the last interface on this connection,
786 // erase the connection
Brad Bishopa098a372022-05-05 15:19:04 -0400787 connectionMap->second.erase(interfaceSet);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500788
789 // Instead of checking if every single path is the endpoint
790 // of an association that needs to be moved to pending,
791 // only check when the only remaining owner of this path is
792 // ourself, which would be because we still own the
793 // association path.
Brad Bishopa098a372022-05-05 15:19:04 -0400794 if ((connectionMap->second.size() == 1) &&
795 (connectionMap->second.begin()->first ==
Brad Bishopa02cd542021-10-12 19:12:42 -0400796 "xyz.openbmc_project.ObjectMapper"))
Matt Spinler9c3d2852019-04-08 15:57:19 -0500797 {
798 // Remove the 2 association D-Bus paths and move the
799 // association to pending.
Brad Bishopa098a372022-05-05 15:19:04 -0400800 moveAssociationToPending(objPath.str, associationMaps,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500801 server);
802 }
Ed Tanous60520632018-06-11 17:46:52 -0700803 }
804 }
805 // If this was the last connection on this object path,
806 // erase the object path
Brad Bishopa098a372022-05-05 15:19:04 -0400807 if (connectionMap->second.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700808 {
Brad Bishopa098a372022-05-05 15:19:04 -0400809 interfaceMap.erase(connectionMap);
Ed Tanous60520632018-06-11 17:46:52 -0700810 }
Matt Spinlera82779f2019-01-09 12:39:42 -0600811
Brad Bishopa098a372022-05-05 15:19:04 -0400812 removeUnneededParents(objPath.str, sender, interfaceMap);
Ed Tanous60520632018-06-11 17:46:52 -0700813 };
814
Patrick Williamscc8070b2022-07-22 19:26:55 -0500815 sdbusplus::bus::match_t interfacesRemoved(
816 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700817 sdbusplus::bus::match::rules::interfacesRemoved(),
818 interfacesRemovedHandler);
819
Patrick Williamscc8070b2022-07-22 19:26:55 -0500820 std::function<void(sdbusplus::message_t & message)>
Brad Bishopa098a372022-05-05 15:19:04 -0400821 associationChangedHandler = [&server, &nameOwners, &interfaceMap](
Patrick Williamscc8070b2022-07-22 19:26:55 -0500822 sdbusplus::message_t& message) {
Matt Spinler8f876a52019-04-15 13:22:50 -0500823 std::string objectName;
Patrick Williams2bb2d6b2020-05-13 17:59:02 -0500824 boost::container::flat_map<std::string,
825 std::variant<std::vector<Association>>>
Matt Spinler8f876a52019-04-15 13:22:50 -0500826 values;
827 message.read(objectName, values);
John Wangd0cf9422019-09-17 16:01:34 +0800828 auto prop = values.find(assocDefsProperty);
Matt Spinler8f876a52019-04-15 13:22:50 -0500829 if (prop != values.end())
830 {
831 std::vector<Association> associations =
Patrick Williamsb05bc122020-05-13 12:21:00 -0500832 std::get<std::vector<Association>>(prop->second);
Matt Spinler8f876a52019-04-15 13:22:50 -0500833
Brad Bishopa098a372022-05-05 15:19:04 -0400834 std::string wellKnown;
835 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
Matt Spinler8f876a52019-04-15 13:22:50 -0500836 {
837 return;
Ed Tanous60520632018-06-11 17:46:52 -0700838 }
Matt Spinler8f876a52019-04-15 13:22:50 -0500839 associationChanged(server, associations, message.get_path(),
Brad Bishopa098a372022-05-05 15:19:04 -0400840 wellKnown, interfaceMap, associationMaps);
Matt Spinler8f876a52019-04-15 13:22:50 -0500841 }
842 };
Patrick Williamscc8070b2022-07-22 19:26:55 -0500843 sdbusplus::bus::match_t assocChangedMatch(
844 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700845 sdbusplus::bus::match::rules::interface(
846 "org.freedesktop.DBus.Properties") +
847 sdbusplus::bus::match::rules::member("PropertiesChanged") +
Matt Spinler8f876a52019-04-15 13:22:50 -0500848 sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
849 associationChangedHandler);
850
Ed Tanous60520632018-06-11 17:46:52 -0700851 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
Brad Bishopa02cd542021-10-12 19:12:42 -0400852 server.add_interface("/xyz/openbmc_project/object_mapper",
853 "xyz.openbmc_project.ObjectMapper");
Ed Tanous60520632018-06-11 17:46:52 -0700854
855 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400856 "GetAncestors", [&interfaceMap](std::string& reqPath,
857 std::vector<std::string>& interfaces) {
858 return getAncestors(interfaceMap, reqPath, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700859 });
860
861 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400862 "GetObject", [&interfaceMap](const std::string& path,
863 std::vector<std::string>& interfaces) {
864 return getObject(interfaceMap, path, interfaces);
865 });
866
867 iface->register_method(
868 "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
Ed Tanous60520632018-06-11 17:46:52 -0700869 std::vector<std::string>& interfaces) {
Brad Bishopa098a372022-05-05 15:19:04 -0400870 return getSubTree(interfaceMap, reqPath, depth, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700871 });
872
873 iface->register_method(
874 "GetSubTreePaths",
Brad Bishopa098a372022-05-05 15:19:04 -0400875 [&interfaceMap](std::string& reqPath, int32_t depth,
876 std::vector<std::string>& interfaces) {
877 return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700878 });
879
880 iface->initialize();
881
882 io.post([&]() {
Brad Bishopa098a372022-05-05 15:19:04 -0400883 doListNames(io, interfaceMap, systemBus.get(), nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500884 associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700885 });
886
Brad Bishopa098a372022-05-05 15:19:04 -0400887 systemBus->request_name("xyz.openbmc_project.ObjectMapper");
Vishwanatha Subbanna64354ef2020-08-21 03:35:26 -0500888
Ed Tanous60520632018-06-11 17:46:52 -0700889 io.run();
890}