blob: a64030aa5a1b86f0ae3d9d1356eb6475e1a1e21b [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
Brad Bishopa83db302020-12-06 14:51:23 -050020#include <phosphor-logging/log.hpp>
21
Patrick Venturea680d1e2018-10-14 13:34:26 -070022#include <algorithm>
23#include <chrono>
24#include <exception>
Kun Yie6b21c72019-03-27 09:53:51 -070025#include <filesystem>
Patrick Venturea680d1e2018-10-14 13:34:26 -070026#include <iostream>
Patrick Venturea680d1e2018-10-14 13:34:26 -070027
Brad Bishop24424982017-01-13 16:37:14 -050028using namespace std::literals::chrono_literals;
29
Brad Bishop49aefb32016-10-19 11:54:14 -040030namespace phosphor
31{
32namespace inventory
33{
34namespace manager
35{
Brad Bishop49aefb32016-10-19 11:54:14 -040036/** @brief Fowrarding signal callback.
37 *
38 * Extracts per-signal specific context and forwards the call to the manager
39 * instance.
40 */
Brad Bishop7b337772017-01-12 16:11:24 -050041auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
Brad Bishop49aefb32016-10-19 11:54:14 -040042{
Brad Bishop7b337772017-01-12 16:11:24 -050043 try
44 {
Brad Bishop49aefb32016-10-19 11:54:14 -040045 auto msg = sdbusplus::message::message(m);
Brad Bishop7b337772017-01-12 16:11:24 -050046 auto& args = *static_cast<Manager::SigArg*>(data);
Brad Bishop49aefb32016-10-19 11:54:14 -040047 sd_bus_message_ref(m);
Brad Bishop7b337772017-01-12 16:11:24 -050048 auto& mgr = *std::get<0>(args);
Brad Bishop615b2a82018-03-29 10:32:41 -040049 mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)),
50 *std::get<2>(args));
Brad Bishop49aefb32016-10-19 11:54:14 -040051 }
Brad Bishop7b337772017-01-12 16:11:24 -050052 catch (const std::exception& e)
53 {
Brad Bishop49aefb32016-10-19 11:54:14 -040054 std::cerr << e.what() << std::endl;
55 }
56
57 return 0;
58}
59
Brad Bishop20c94352020-12-06 20:23:56 -050060Manager::Manager(sdbusplus::bus::bus&& bus, const char* root) :
Brad Bishop4627a9c2020-12-06 19:26:57 -050061 ServerObject<ManagerIface>(bus, root), _root(root), _bus(std::move(bus)),
62 _manager(_bus, root),
Matt Spinler852db672019-03-06 13:46:14 -060063#ifdef CREATE_ASSOCIATIONS
Brad Bishop4627a9c2020-12-06 19:26:57 -050064 _associations(_bus),
Matt Spinler852db672019-03-06 13:46:14 -060065#endif
Brad Bishop4627a9c2020-12-06 19:26:57 -050066 _status(ManagerStatus::STARTING)
Brad Bishop49aefb32016-10-19 11:54:14 -040067{
Brad Bishop7b337772017-01-12 16:11:24 -050068 for (auto& group : _events)
Brad Bishop68c80832016-11-29 16:41:32 -050069 {
Brad Bishop615b2a82018-03-29 10:32:41 -040070 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop68c80832016-11-29 16:41:32 -050071 {
Brad Bishop615b2a82018-03-29 10:32:41 -040072 if (pEvent->type != Event::Type::DBUS_SIGNAL)
Brad Bishop7b337772017-01-12 16:11:24 -050073 {
Brad Bishop68c80832016-11-29 16:41:32 -050074 continue;
Brad Bishop7b337772017-01-12 16:11:24 -050075 }
Brad Bishop4f20a3e2016-11-29 15:21:46 -050076
Brad Bishop68c80832016-11-29 16:41:32 -050077 // Create a callback context for this event group.
Brad Bishop615b2a82018-03-29 10:32:41 -040078 auto dbusEvent = static_cast<DbusSignal*>(pEvent.get());
Brad Bishop68c80832016-11-29 16:41:32 -050079
80 // Go ahead and store an iterator pointing at
81 // the event data to avoid lookups later since
82 // additional signal callbacks aren't added
83 // after the manager is constructed.
84 _sigargs.emplace_back(
Brad Bishop615b2a82018-03-29 10:32:41 -040085 std::make_unique<SigArg>(this, dbusEvent, &group));
Brad Bishop68c80832016-11-29 16:41:32 -050086
87 // Register our callback and the context for
88 // each signal event.
Brad Bishop615b2a82018-03-29 10:32:41 -040089 _matches.emplace_back(_bus, dbusEvent->signature, _signal,
90 _sigargs.back().get());
Brad Bishop68c80832016-11-29 16:41:32 -050091 }
Brad Bishop49aefb32016-10-19 11:54:14 -040092 }
93
Deepak Kodihallib28990f2017-08-08 07:19:34 -050094 // Restore any persistent inventory
95 restore();
Brad Bishop49aefb32016-10-19 11:54:14 -040096}
97
98void Manager::shutdown() noexcept
99{
Brad Bishop4627a9c2020-12-06 19:26:57 -0500100 _status = ManagerStatus::STOPPING;
Brad Bishop49aefb32016-10-19 11:54:14 -0400101}
102
Brad Bishop20c94352020-12-06 20:23:56 -0500103void Manager::run(const char* busname)
Brad Bishop49aefb32016-10-19 11:54:14 -0400104{
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500105 sdbusplus::message::message unusedMsg{nullptr};
106
107 // Run startup events.
108 for (auto& group : _events)
109 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400110 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500111 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400112 if (pEvent->type == Event::Type::STARTUP)
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500113 {
114 handleEvent(unusedMsg, *pEvent, group);
115 }
116 }
117 }
118
Brad Bishop4627a9c2020-12-06 19:26:57 -0500119 _status = ManagerStatus::RUNNING;
Brad Bishop20c94352020-12-06 20:23:56 -0500120 _bus.request_name(busname);
Brad Bishop4627a9c2020-12-06 19:26:57 -0500121
122 while (_status != ManagerStatus::STOPPING)
Brad Bishop7b337772017-01-12 16:11:24 -0500123 {
124 try
125 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400126 _bus.process_discard();
Brad Bishop24424982017-01-13 16:37:14 -0500127 _bus.wait((5000000us).count());
Brad Bishop49aefb32016-10-19 11:54:14 -0400128 }
Brad Bishop7b337772017-01-12 16:11:24 -0500129 catch (const std::exception& e)
130 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400131 std::cerr << e.what() << std::endl;
132 }
133 }
134}
135
Brad Bishop615b2a82018-03-29 10:32:41 -0400136void Manager::updateInterfaces(const sdbusplus::message::object_path& path,
137 const Object& interfaces,
138 ObjectReferences::iterator pos, bool newObject,
139 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500140{
141 auto& refaces = pos->second;
142 auto ifaceit = interfaces.cbegin();
143 auto opsit = _makers.cbegin();
144 auto refaceit = refaces.begin();
145 std::vector<std::string> signals;
146
147 while (ifaceit != interfaces.cend())
148 {
149 try
150 {
151 // Find the binding ops for this interface.
Brad Bishop615b2a82018-03-29 10:32:41 -0400152 opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first,
153 compareFirst(_makers.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500154
155 if (opsit == _makers.cend() || opsit->first != ifaceit->first)
156 {
157 // This interface is not supported.
Brad Bishop615b2a82018-03-29 10:32:41 -0400158 throw InterfaceError("Encountered unsupported interface.",
159 ifaceit->first);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500160 }
161
162 // Find the binding insertion point or the binding to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400163 refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first,
164 compareFirst(refaces.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500165
166 if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
167 {
168 // Add the new interface.
Brad Bishop02763c62018-12-12 22:02:07 -0500169 auto& ctor = std::get<MakeInterfaceType>(opsit->second);
Brad Bishop23a8d932020-12-06 19:40:13 -0500170 // skipSignal = true here to avoid getting PropertiesChanged
171 // signals while the interface is constructed. We'll emit an
172 // ObjectManager signal for this interface below.
Brad Bishop79ccaf72017-01-22 16:00:50 -0500173 refaceit = refaces.insert(
Brad Bishope96f2aa2020-12-06 19:09:09 -0500174 refaceit, std::make_pair(ifaceit->first,
175 ctor(_bus, path.str.c_str(),
Brad Bishop23a8d932020-12-06 19:40:13 -0500176 ifaceit->second, true)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500177 signals.push_back(ifaceit->first);
178 }
179 else
180 {
181 // Set the new property values.
Brad Bishop02763c62018-12-12 22:02:07 -0500182 auto& assign = std::get<AssignInterfaceType>(opsit->second);
Brad Bishop23a8d932020-12-06 19:40:13 -0500183 assign(ifaceit->second, refaceit->second,
184 _status != ManagerStatus::RUNNING);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500185 }
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500186 if (!restoreFromCache)
187 {
Brad Bishop02763c62018-12-12 22:02:07 -0500188 auto& serialize =
189 std::get<SerializeInterfaceType<SerialOps>>(opsit->second);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500190 serialize(path, ifaceit->first, refaceit->second);
191 }
192 else
193 {
Brad Bishop02763c62018-12-12 22:02:07 -0500194 auto& deserialize =
195 std::get<DeserializeInterfaceType<SerialOps>>(
196 opsit->second);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500197 deserialize(path, ifaceit->first, refaceit->second);
198 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500199 }
200 catch (const InterfaceError& e)
201 {
202 // Reset the binding ops iterator since we are
203 // at the end.
204 opsit = _makers.cbegin();
205 e.log();
206 }
207
208 ++ifaceit;
209 }
210
Brad Bishop23a8d932020-12-06 19:40:13 -0500211 if (_status == ManagerStatus::RUNNING)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500212 {
Brad Bishop23a8d932020-12-06 19:40:13 -0500213 if (newObject)
214 {
215 _bus.emit_object_added(path.str.c_str());
216 }
217 else if (!signals.empty())
218 {
219 _bus.emit_interfaces_added(path.str.c_str(), signals);
220 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500221 }
222}
223
224void Manager::updateObjects(
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500225 const std::map<sdbusplus::message::object_path, Object>& objs,
226 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500227{
228 auto objit = objs.cbegin();
229 auto refit = _refs.begin();
230 std::string absPath;
231 bool newObj;
232
233 while (objit != objs.cend())
234 {
235 // Find the insertion point or the object to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400236 refit = std::lower_bound(refit, _refs.end(), objit->first,
237 compareFirst(RelPathCompare(_root)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500238
239 absPath.assign(_root);
240 absPath.append(objit->first);
241
242 newObj = false;
243 if (refit == _refs.end() || refit->first != absPath)
244 {
245 refit = _refs.insert(
Brad Bishop615b2a82018-03-29 10:32:41 -0400246 refit, std::make_pair(absPath, decltype(_refs)::mapped_type()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500247 newObj = true;
248 }
249
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500250 updateInterfaces(absPath, objit->second, refit, newObj,
251 restoreFromCache);
Matt Spinler852db672019-03-06 13:46:14 -0600252#ifdef CREATE_ASSOCIATIONS
253 if (newObj)
254 {
Brad Bishop23a8d932020-12-06 19:40:13 -0500255 _associations.createAssociations(absPath,
Brad Bishopee294d62021-01-13 16:14:29 -0500256 _status != ManagerStatus::RUNNING);
Matt Spinler852db672019-03-06 13:46:14 -0600257 }
258#endif
Brad Bishop79ccaf72017-01-22 16:00:50 -0500259 ++objit;
260 }
261}
262
Brad Bishop03f4cd92017-02-03 15:17:21 -0500263void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
Brad Bishop49aefb32016-10-19 11:54:14 -0400264{
Brad Bishopcda036f2017-02-15 10:06:48 -0500265 updateObjects(objs);
Brad Bishop49aefb32016-10-19 11:54:14 -0400266}
267
Brad Bishop615b2a82018-03-29 10:32:41 -0400268void Manager::handleEvent(sdbusplus::message::message& msg, const Event& event,
269 const EventInfo& info)
Brad Bishop49aefb32016-10-19 11:54:14 -0400270{
Brad Bishop7b337772017-01-12 16:11:24 -0500271 auto& actions = std::get<1>(info);
Brad Bishop3d57f502016-10-19 12:18:41 -0400272
Brad Bishop48547a82017-01-19 15:12:50 -0500273 for (auto& f : event)
Brad Bishop7b337772017-01-12 16:11:24 -0500274 {
Brad Bishop07934a62017-02-08 23:34:59 -0500275 if (!f(_bus, msg, *this))
Brad Bishop7b337772017-01-12 16:11:24 -0500276 {
Brad Bishop064c94a2017-01-21 21:33:30 -0500277 return;
Brad Bishop7b337772017-01-12 16:11:24 -0500278 }
Brad Bishop3d57f502016-10-19 12:18:41 -0400279 }
Brad Bishop064c94a2017-01-21 21:33:30 -0500280 for (auto& action : actions)
281 {
Brad Bishop07934a62017-02-08 23:34:59 -0500282 action(_bus, *this);
Brad Bishop064c94a2017-01-21 21:33:30 -0500283 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400284}
285
Brad Bishop615b2a82018-03-29 10:32:41 -0400286void Manager::destroyObjects(const std::vector<const char*>& paths)
Brad Bishop656a7d02016-10-19 22:20:02 -0400287{
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500288 std::string p;
289
Brad Bishop7b7e7122017-01-21 21:21:46 -0500290 for (const auto& path : paths)
291 {
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500292 p.assign(_root);
293 p.append(path);
294 _bus.emit_object_removed(p.c_str());
295 _refs.erase(p);
Brad Bishop7b7e7122017-01-21 21:21:46 -0500296 }
Brad Bishop656a7d02016-10-19 22:20:02 -0400297}
298
Brad Bishopeb68a682017-01-22 00:58:54 -0500299void Manager::createObjects(
300 const std::map<sdbusplus::message::object_path, Object>& objs)
301{
Brad Bishopcda036f2017-02-15 10:06:48 -0500302 updateObjects(objs);
Brad Bishopeb68a682017-01-22 00:58:54 -0500303}
304
Brad Bishop25d54b52018-11-21 12:57:51 -0500305std::any& Manager::getInterfaceHolder(const char* path, const char* interface)
Brad Bishopb83a21e2016-11-30 13:43:37 -0500306{
Brad Bishop25d54b52018-11-21 12:57:51 -0500307 return const_cast<std::any&>(
Brad Bishop615b2a82018-03-29 10:32:41 -0400308 const_cast<const Manager*>(this)->getInterfaceHolder(path, interface));
Brad Bishopb83a21e2016-11-30 13:43:37 -0500309}
310
Brad Bishop25d54b52018-11-21 12:57:51 -0500311const std::any& Manager::getInterfaceHolder(const char* path,
312 const char* interface) const
Brad Bishopb83a21e2016-11-30 13:43:37 -0500313{
314 std::string p{path};
315 auto oit = _refs.find(_root + p);
Brad Bishop7b337772017-01-12 16:11:24 -0500316 if (oit == _refs.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400317 throw std::runtime_error(_root + p + " was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500318
Brad Bishop7b337772017-01-12 16:11:24 -0500319 auto& obj = oit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500320 auto iit = obj.find(interface);
Brad Bishop7b337772017-01-12 16:11:24 -0500321 if (iit == obj.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400322 throw std::runtime_error("interface was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500323
Brad Bishop150147a2017-02-08 23:57:46 -0500324 return iit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500325}
326
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500327void Manager::restore()
328{
Kun Yie6b21c72019-03-27 09:53:51 -0700329 namespace fs = std::filesystem;
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500330
331 if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
332 {
333 return;
334 }
335
336 static const std::string remove =
337 std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
338
339 std::map<sdbusplus::message::object_path, Object> objects;
340 for (const auto& dirent :
341 fs::recursive_directory_iterator(PIM_PERSIST_PATH))
342 {
343 const auto& path = dirent.path();
344 if (fs::is_regular_file(path))
345 {
346 auto ifaceName = path.filename().string();
347 auto objPath = path.parent_path().string();
348 objPath.erase(0, remove.length());
349 auto objit = objects.find(objPath);
350 Interface propertyMap{};
351 if (objects.end() != objit)
352 {
353 auto& object = objit->second;
354 object.emplace(std::move(ifaceName), std::move(propertyMap));
355 }
356 else
357 {
358 Object object;
359 object.emplace(std::move(ifaceName), std::move(propertyMap));
360 objects.emplace(std::move(objPath), std::move(object));
361 }
362 }
363 }
364 if (!objects.empty())
365 {
366 auto restoreFromCache = true;
367 updateObjects(objects, restoreFromCache);
368 }
369}
370
Brad Bishop49aefb32016-10-19 11:54:14 -0400371} // namespace manager
372} // namespace inventory
373} // namespace phosphor
374
375// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4