blob: f9e40c65ba75ec1ff84654bd8536193865add0d5 [file] [log] [blame]
Brad Bishop49aefb32016-10-19 11:54:14 -04001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brad Bishop49aefb32016-10-19 11:54:14 -040016#include "manager.hpp"
Patrick Venturea680d1e2018-10-14 13:34:26 -070017
Brad Bishop79ccaf72017-01-22 16:00:50 -050018#include "errors.hpp"
Brad Bishop49aefb32016-10-19 11:54:14 -040019
Patrick Venturea680d1e2018-10-14 13:34:26 -070020#include <algorithm>
21#include <chrono>
22#include <exception>
Kun Yie6b21c72019-03-27 09:53:51 -070023#include <filesystem>
Patrick Venturea680d1e2018-10-14 13:34:26 -070024#include <iostream>
Patrick Venturea680d1e2018-10-14 13:34:26 -070025
Brad Bishop24424982017-01-13 16:37:14 -050026using namespace std::literals::chrono_literals;
27
Brad Bishop49aefb32016-10-19 11:54:14 -040028namespace phosphor
29{
30namespace inventory
31{
32namespace manager
33{
Brad Bishop49aefb32016-10-19 11:54:14 -040034/** @brief Fowrarding signal callback.
35 *
36 * Extracts per-signal specific context and forwards the call to the manager
37 * instance.
38 */
George Liu23314a52022-04-13 18:26:03 +080039auto _signal(sd_bus_message* m, void* data, sd_bus_error* /* e */) noexcept
Brad Bishop49aefb32016-10-19 11:54:14 -040040{
Brad Bishop7b337772017-01-12 16:11:24 -050041 try
42 {
Patrick Williams563306f2022-07-22 19:26:52 -050043 auto msg = sdbusplus::message_t(m);
Brad Bishop7b337772017-01-12 16:11:24 -050044 auto& args = *static_cast<Manager::SigArg*>(data);
Brad Bishop49aefb32016-10-19 11:54:14 -040045 sd_bus_message_ref(m);
Brad Bishop7b337772017-01-12 16:11:24 -050046 auto& mgr = *std::get<0>(args);
Brad Bishop615b2a82018-03-29 10:32:41 -040047 mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)),
48 *std::get<2>(args));
Brad Bishop49aefb32016-10-19 11:54:14 -040049 }
Brad Bishop7b337772017-01-12 16:11:24 -050050 catch (const std::exception& e)
51 {
Brad Bishop49aefb32016-10-19 11:54:14 -040052 std::cerr << e.what() << std::endl;
53 }
54
55 return 0;
56}
57
Patrick Williams563306f2022-07-22 19:26:52 -050058Manager::Manager(sdbusplus::bus_t&& bus, const char* root) :
Brad Bishop4627a9c2020-12-06 19:26:57 -050059 ServerObject<ManagerIface>(bus, root), _root(root), _bus(std::move(bus)),
60 _manager(_bus, root),
Matt Spinler852db672019-03-06 13:46:14 -060061#ifdef CREATE_ASSOCIATIONS
Brad Bishop4627a9c2020-12-06 19:26:57 -050062 _associations(_bus),
Matt Spinler852db672019-03-06 13:46:14 -060063#endif
Brad Bishop4627a9c2020-12-06 19:26:57 -050064 _status(ManagerStatus::STARTING)
Brad Bishop49aefb32016-10-19 11:54:14 -040065{
Brad Bishop7b337772017-01-12 16:11:24 -050066 for (auto& group : _events)
Brad Bishop68c80832016-11-29 16:41:32 -050067 {
Brad Bishop615b2a82018-03-29 10:32:41 -040068 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop68c80832016-11-29 16:41:32 -050069 {
Brad Bishop615b2a82018-03-29 10:32:41 -040070 if (pEvent->type != Event::Type::DBUS_SIGNAL)
Brad Bishop7b337772017-01-12 16:11:24 -050071 {
Brad Bishop68c80832016-11-29 16:41:32 -050072 continue;
Brad Bishop7b337772017-01-12 16:11:24 -050073 }
Brad Bishop4f20a3e2016-11-29 15:21:46 -050074
Brad Bishop68c80832016-11-29 16:41:32 -050075 // Create a callback context for this event group.
Brad Bishop615b2a82018-03-29 10:32:41 -040076 auto dbusEvent = static_cast<DbusSignal*>(pEvent.get());
Brad Bishop68c80832016-11-29 16:41:32 -050077
78 // Go ahead and store an iterator pointing at
79 // the event data to avoid lookups later since
80 // additional signal callbacks aren't added
81 // after the manager is constructed.
82 _sigargs.emplace_back(
Brad Bishop615b2a82018-03-29 10:32:41 -040083 std::make_unique<SigArg>(this, dbusEvent, &group));
Brad Bishop68c80832016-11-29 16:41:32 -050084
85 // Register our callback and the context for
86 // each signal event.
Brad Bishop615b2a82018-03-29 10:32:41 -040087 _matches.emplace_back(_bus, dbusEvent->signature, _signal,
88 _sigargs.back().get());
Brad Bishop68c80832016-11-29 16:41:32 -050089 }
Brad Bishop49aefb32016-10-19 11:54:14 -040090 }
91
Deepak Kodihallib28990f2017-08-08 07:19:34 -050092 // Restore any persistent inventory
93 restore();
Brad Bishop49aefb32016-10-19 11:54:14 -040094}
95
96void Manager::shutdown() noexcept
97{
Brad Bishop4627a9c2020-12-06 19:26:57 -050098 _status = ManagerStatus::STOPPING;
Brad Bishop49aefb32016-10-19 11:54:14 -040099}
100
Brad Bishop20c94352020-12-06 20:23:56 -0500101void Manager::run(const char* busname)
Brad Bishop49aefb32016-10-19 11:54:14 -0400102{
Patrick Williams563306f2022-07-22 19:26:52 -0500103 sdbusplus::message_t unusedMsg{nullptr};
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500104
105 // Run startup events.
106 for (auto& group : _events)
107 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400108 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500109 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400110 if (pEvent->type == Event::Type::STARTUP)
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500111 {
112 handleEvent(unusedMsg, *pEvent, group);
113 }
114 }
115 }
116
Brad Bishop4627a9c2020-12-06 19:26:57 -0500117 _status = ManagerStatus::RUNNING;
Brad Bishop20c94352020-12-06 20:23:56 -0500118 _bus.request_name(busname);
Brad Bishop4627a9c2020-12-06 19:26:57 -0500119
120 while (_status != ManagerStatus::STOPPING)
Brad Bishop7b337772017-01-12 16:11:24 -0500121 {
122 try
123 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400124 _bus.process_discard();
Brad Bishop24424982017-01-13 16:37:14 -0500125 _bus.wait((5000000us).count());
Brad Bishop49aefb32016-10-19 11:54:14 -0400126 }
Brad Bishop7b337772017-01-12 16:11:24 -0500127 catch (const std::exception& e)
128 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400129 std::cerr << e.what() << std::endl;
130 }
131 }
132}
133
Patrick Williamsd8fba8b2024-08-16 15:20:15 -0400134void Manager::updateInterfaces(
135 const sdbusplus::message::object_path& path, const Object& interfaces,
136 ObjectReferences::iterator pos, bool newObject, bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500137{
138 auto& refaces = pos->second;
139 auto ifaceit = interfaces.cbegin();
140 auto opsit = _makers.cbegin();
141 auto refaceit = refaces.begin();
142 std::vector<std::string> signals;
143
144 while (ifaceit != interfaces.cend())
145 {
146 try
147 {
148 // Find the binding ops for this interface.
Brad Bishop615b2a82018-03-29 10:32:41 -0400149 opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first,
150 compareFirst(_makers.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500151
152 if (opsit == _makers.cend() || opsit->first != ifaceit->first)
153 {
154 // This interface is not supported.
Brad Bishop615b2a82018-03-29 10:32:41 -0400155 throw InterfaceError("Encountered unsupported interface.",
156 ifaceit->first);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500157 }
158
159 // Find the binding insertion point or the binding to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400160 refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first,
161 compareFirst(refaces.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500162
163 if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
164 {
165 // Add the new interface.
Brad Bishop02763c62018-12-12 22:02:07 -0500166 auto& ctor = std::get<MakeInterfaceType>(opsit->second);
Brad Bishop23a8d932020-12-06 19:40:13 -0500167 // skipSignal = true here to avoid getting PropertiesChanged
168 // signals while the interface is constructed. We'll emit an
169 // ObjectManager signal for this interface below.
Brad Bishop79ccaf72017-01-22 16:00:50 -0500170 refaceit = refaces.insert(
Brad Bishope96f2aa2020-12-06 19:09:09 -0500171 refaceit, std::make_pair(ifaceit->first,
172 ctor(_bus, path.str.c_str(),
Brad Bishop23a8d932020-12-06 19:40:13 -0500173 ifaceit->second, true)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500174 signals.push_back(ifaceit->first);
175 }
176 else
177 {
178 // Set the new property values.
Brad Bishop02763c62018-12-12 22:02:07 -0500179 auto& assign = std::get<AssignInterfaceType>(opsit->second);
Brad Bishop23a8d932020-12-06 19:40:13 -0500180 assign(ifaceit->second, refaceit->second,
181 _status != ManagerStatus::RUNNING);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500182 }
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500183 if (!restoreFromCache)
184 {
Brad Bishop02763c62018-12-12 22:02:07 -0500185 auto& serialize =
186 std::get<SerializeInterfaceType<SerialOps>>(opsit->second);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500187 serialize(path, ifaceit->first, refaceit->second);
188 }
189 else
190 {
Brad Bishop02763c62018-12-12 22:02:07 -0500191 auto& deserialize =
192 std::get<DeserializeInterfaceType<SerialOps>>(
193 opsit->second);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500194 deserialize(path, ifaceit->first, refaceit->second);
195 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500196 }
197 catch (const InterfaceError& e)
198 {
199 // Reset the binding ops iterator since we are
200 // at the end.
201 opsit = _makers.cbegin();
202 e.log();
203 }
204
205 ++ifaceit;
206 }
207
Brad Bishop23a8d932020-12-06 19:40:13 -0500208 if (_status == ManagerStatus::RUNNING)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500209 {
Brad Bishop23a8d932020-12-06 19:40:13 -0500210 if (newObject)
211 {
212 _bus.emit_object_added(path.str.c_str());
213 }
214 else if (!signals.empty())
215 {
216 _bus.emit_interfaces_added(path.str.c_str(), signals);
217 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500218 }
219}
220
221void Manager::updateObjects(
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500222 const std::map<sdbusplus::message::object_path, Object>& objs,
223 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500224{
225 auto objit = objs.cbegin();
226 auto refit = _refs.begin();
227 std::string absPath;
228 bool newObj;
229
230 while (objit != objs.cend())
231 {
232 // Find the insertion point or the object to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400233 refit = std::lower_bound(refit, _refs.end(), objit->first,
234 compareFirst(RelPathCompare(_root)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500235
236 absPath.assign(_root);
237 absPath.append(objit->first);
238
239 newObj = false;
240 if (refit == _refs.end() || refit->first != absPath)
241 {
242 refit = _refs.insert(
Brad Bishop615b2a82018-03-29 10:32:41 -0400243 refit, std::make_pair(absPath, decltype(_refs)::mapped_type()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500244 newObj = true;
245 }
246
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500247 updateInterfaces(absPath, objit->second, refit, newObj,
248 restoreFromCache);
Matt Spinler852db672019-03-06 13:46:14 -0600249#ifdef CREATE_ASSOCIATIONS
Matt Spinler59521e82021-02-11 13:41:06 -0600250 if (!_associations.pendingCondition() && newObj)
Matt Spinler852db672019-03-06 13:46:14 -0600251 {
Brad Bishop23a8d932020-12-06 19:40:13 -0500252 _associations.createAssociations(absPath,
Brad Bishopee294d62021-01-13 16:14:29 -0500253 _status != ManagerStatus::RUNNING);
Matt Spinler852db672019-03-06 13:46:14 -0600254 }
Matt Spinler59521e82021-02-11 13:41:06 -0600255 else if (!restoreFromCache &&
256 _associations.conditionMatch(objit->first, objit->second))
257 {
258 // The objit path/interface/property matched a pending condition.
259 // Now the associations are valid so attempt to create them against
260 // all existing objects. If this was the restoreFromCache path,
261 // objit doesn't contain property values so don't bother checking.
262 std::for_each(_refs.begin(), _refs.end(), [this](const auto& ref) {
263 _associations.createAssociations(
264 ref.first, _status != ManagerStatus::RUNNING);
265 });
266 }
Matt Spinler852db672019-03-06 13:46:14 -0600267#endif
Brad Bishop79ccaf72017-01-22 16:00:50 -0500268 ++objit;
269 }
270}
271
Brad Bishop03f4cd92017-02-03 15:17:21 -0500272void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
Brad Bishop49aefb32016-10-19 11:54:14 -0400273{
Brad Bishopcda036f2017-02-15 10:06:48 -0500274 updateObjects(objs);
Brad Bishop49aefb32016-10-19 11:54:14 -0400275}
276
Patrick Williams563306f2022-07-22 19:26:52 -0500277void Manager::handleEvent(sdbusplus::message_t& msg, const Event& event,
Brad Bishop615b2a82018-03-29 10:32:41 -0400278 const EventInfo& info)
Brad Bishop49aefb32016-10-19 11:54:14 -0400279{
Brad Bishop7b337772017-01-12 16:11:24 -0500280 auto& actions = std::get<1>(info);
Brad Bishop3d57f502016-10-19 12:18:41 -0400281
Brad Bishop48547a82017-01-19 15:12:50 -0500282 for (auto& f : event)
Brad Bishop7b337772017-01-12 16:11:24 -0500283 {
Brad Bishop07934a62017-02-08 23:34:59 -0500284 if (!f(_bus, msg, *this))
Brad Bishop7b337772017-01-12 16:11:24 -0500285 {
Brad Bishop064c94a2017-01-21 21:33:30 -0500286 return;
Brad Bishop7b337772017-01-12 16:11:24 -0500287 }
Brad Bishop3d57f502016-10-19 12:18:41 -0400288 }
Brad Bishop064c94a2017-01-21 21:33:30 -0500289 for (auto& action : actions)
290 {
Brad Bishop07934a62017-02-08 23:34:59 -0500291 action(_bus, *this);
Brad Bishop064c94a2017-01-21 21:33:30 -0500292 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400293}
294
Brad Bishop615b2a82018-03-29 10:32:41 -0400295void Manager::destroyObjects(const std::vector<const char*>& paths)
Brad Bishop656a7d02016-10-19 22:20:02 -0400296{
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500297 std::string p;
298
Brad Bishop7b7e7122017-01-21 21:21:46 -0500299 for (const auto& path : paths)
300 {
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500301 p.assign(_root);
302 p.append(path);
303 _bus.emit_object_removed(p.c_str());
304 _refs.erase(p);
Brad Bishop7b7e7122017-01-21 21:21:46 -0500305 }
Brad Bishop656a7d02016-10-19 22:20:02 -0400306}
307
Brad Bishopeb68a682017-01-22 00:58:54 -0500308void Manager::createObjects(
309 const std::map<sdbusplus::message::object_path, Object>& objs)
310{
Brad Bishopcda036f2017-02-15 10:06:48 -0500311 updateObjects(objs);
Brad Bishopeb68a682017-01-22 00:58:54 -0500312}
313
Brad Bishop25d54b52018-11-21 12:57:51 -0500314std::any& Manager::getInterfaceHolder(const char* path, const char* interface)
Brad Bishopb83a21e2016-11-30 13:43:37 -0500315{
Brad Bishop25d54b52018-11-21 12:57:51 -0500316 return const_cast<std::any&>(
Brad Bishop615b2a82018-03-29 10:32:41 -0400317 const_cast<const Manager*>(this)->getInterfaceHolder(path, interface));
Brad Bishopb83a21e2016-11-30 13:43:37 -0500318}
319
Patrick Williamsd8fba8b2024-08-16 15:20:15 -0400320const std::any&
321 Manager::getInterfaceHolder(const char* path, const char* interface) const
Brad Bishopb83a21e2016-11-30 13:43:37 -0500322{
323 std::string p{path};
324 auto oit = _refs.find(_root + p);
Brad Bishop7b337772017-01-12 16:11:24 -0500325 if (oit == _refs.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400326 throw std::runtime_error(_root + p + " was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500327
Brad Bishop7b337772017-01-12 16:11:24 -0500328 auto& obj = oit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500329 auto iit = obj.find(interface);
Brad Bishop7b337772017-01-12 16:11:24 -0500330 if (iit == obj.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400331 throw std::runtime_error("interface was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500332
Brad Bishop150147a2017-02-08 23:57:46 -0500333 return iit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500334}
335
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500336void Manager::restore()
337{
Kun Yie6b21c72019-03-27 09:53:51 -0700338 namespace fs = std::filesystem;
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500339
340 if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
341 {
342 return;
343 }
344
Patrick Williamsd8fba8b2024-08-16 15:20:15 -0400345 static const std::string remove =
346 std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500347
348 std::map<sdbusplus::message::object_path, Object> objects;
349 for (const auto& dirent :
350 fs::recursive_directory_iterator(PIM_PERSIST_PATH))
351 {
352 const auto& path = dirent.path();
353 if (fs::is_regular_file(path))
354 {
355 auto ifaceName = path.filename().string();
356 auto objPath = path.parent_path().string();
357 objPath.erase(0, remove.length());
358 auto objit = objects.find(objPath);
359 Interface propertyMap{};
360 if (objects.end() != objit)
361 {
362 auto& object = objit->second;
363 object.emplace(std::move(ifaceName), std::move(propertyMap));
364 }
365 else
366 {
367 Object object;
368 object.emplace(std::move(ifaceName), std::move(propertyMap));
369 objects.emplace(std::move(objPath), std::move(object));
370 }
371 }
372 }
373 if (!objects.empty())
374 {
375 auto restoreFromCache = true;
376 updateObjects(objects, restoreFromCache);
Matt Spinler59521e82021-02-11 13:41:06 -0600377
378#ifdef CREATE_ASSOCIATIONS
379 // There may be conditional associations waiting to be loaded
380 // based on certain path/interface/property values. Now that
381 // _refs contains all objects with their property values, check
382 // which property values the conditions need and set them in the
383 // condition structure entries, using the actualValue field. Then
384 // the associations manager can check if the conditions are met.
385 if (_associations.pendingCondition())
386 {
387 ObjectReferences::iterator refIt;
388 InterfaceComposite::iterator ifaceIt;
389
390 auto& conditions = _associations.getConditions();
391 for (auto& condition : conditions)
392 {
393 refIt = _refs.find(_root + condition.path);
394 if (refIt != _refs.end())
395 {
396 ifaceIt = refIt->second.find(condition.interface);
397 }
398
399 if ((refIt != _refs.end()) && (ifaceIt != refIt->second.end()))
400 {
401 const auto& maker = _makers.find(condition.interface);
402 if (maker != _makers.end())
403 {
404 auto& getProperty =
405 std::get<GetPropertyValueType>(maker->second);
406
Patrick Williamsd8fba8b2024-08-16 15:20:15 -0400407 condition.actualValue =
408 getProperty(condition.property, ifaceIt->second);
Matt Spinler59521e82021-02-11 13:41:06 -0600409 }
410 }
411 }
412
413 // Check if a property value in a condition matches an
414 // actual property value just saved. If one did, now the
415 // associations file is valid so create its associations.
416 if (_associations.conditionMatch())
417 {
Patrick Williamsd8fba8b2024-08-16 15:20:15 -0400418 std::for_each(
419 _refs.begin(), _refs.end(), [this](const auto& ref) {
420 _associations.createAssociations(
421 ref.first, _status != ManagerStatus::RUNNING);
422 });
Matt Spinler59521e82021-02-11 13:41:06 -0600423 }
424 }
425#endif
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500426 }
427}
428
Brad Bishop49aefb32016-10-19 11:54:14 -0400429} // namespace manager
430} // namespace inventory
431} // namespace phosphor
432
433// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4