blob: fd33c80af21f2977fd0bdb5c41d3422472b97451 [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>
23#include <experimental/filesystem>
24#include <iostream>
25#include <phosphor-logging/log.hpp>
26
Brad Bishop24424982017-01-13 16:37:14 -050027using namespace std::literals::chrono_literals;
28
Brad Bishop49aefb32016-10-19 11:54:14 -040029namespace phosphor
30{
31namespace inventory
32{
33namespace manager
34{
Brad Bishop49aefb32016-10-19 11:54:14 -040035/** @brief Fowrarding signal callback.
36 *
37 * Extracts per-signal specific context and forwards the call to the manager
38 * instance.
39 */
Brad Bishop7b337772017-01-12 16:11:24 -050040auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
Brad Bishop49aefb32016-10-19 11:54:14 -040041{
Brad Bishop7b337772017-01-12 16:11:24 -050042 try
43 {
Brad Bishop49aefb32016-10-19 11:54:14 -040044 auto msg = sdbusplus::message::message(m);
Brad Bishop7b337772017-01-12 16:11:24 -050045 auto& args = *static_cast<Manager::SigArg*>(data);
Brad Bishop49aefb32016-10-19 11:54:14 -040046 sd_bus_message_ref(m);
Brad Bishop7b337772017-01-12 16:11:24 -050047 auto& mgr = *std::get<0>(args);
Brad Bishop615b2a82018-03-29 10:32:41 -040048 mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)),
49 *std::get<2>(args));
Brad Bishop49aefb32016-10-19 11:54:14 -040050 }
Brad Bishop7b337772017-01-12 16:11:24 -050051 catch (const std::exception& e)
52 {
Brad Bishop49aefb32016-10-19 11:54:14 -040053 std::cerr << e.what() << std::endl;
54 }
55
56 return 0;
57}
58
Brad Bishop615b2a82018-03-29 10:32:41 -040059Manager::Manager(sdbusplus::bus::bus&& bus, const char* busname,
60 const char* root, const char* iface) :
Brad Bishop12f8a3c2017-02-09 00:02:00 -050061 ServerObject<ManagerIface>(bus, root),
Brad Bishop615b2a82018-03-29 10:32:41 -040062 _shutdown(false), _root(root), _bus(std::move(bus)), _manager(_bus, root)
Brad Bishop49aefb32016-10-19 11:54:14 -040063{
Brad Bishop7b337772017-01-12 16:11:24 -050064 for (auto& group : _events)
Brad Bishop68c80832016-11-29 16:41:32 -050065 {
Brad Bishop615b2a82018-03-29 10:32:41 -040066 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop68c80832016-11-29 16:41:32 -050067 {
Brad Bishop615b2a82018-03-29 10:32:41 -040068 if (pEvent->type != Event::Type::DBUS_SIGNAL)
Brad Bishop7b337772017-01-12 16:11:24 -050069 {
Brad Bishop68c80832016-11-29 16:41:32 -050070 continue;
Brad Bishop7b337772017-01-12 16:11:24 -050071 }
Brad Bishop4f20a3e2016-11-29 15:21:46 -050072
Brad Bishop68c80832016-11-29 16:41:32 -050073 // Create a callback context for this event group.
Brad Bishop615b2a82018-03-29 10:32:41 -040074 auto dbusEvent = static_cast<DbusSignal*>(pEvent.get());
Brad Bishop68c80832016-11-29 16:41:32 -050075
76 // Go ahead and store an iterator pointing at
77 // the event data to avoid lookups later since
78 // additional signal callbacks aren't added
79 // after the manager is constructed.
80 _sigargs.emplace_back(
Brad Bishop615b2a82018-03-29 10:32:41 -040081 std::make_unique<SigArg>(this, dbusEvent, &group));
Brad Bishop68c80832016-11-29 16:41:32 -050082
83 // Register our callback and the context for
84 // each signal event.
Brad Bishop615b2a82018-03-29 10:32:41 -040085 _matches.emplace_back(_bus, dbusEvent->signature, _signal,
86 _sigargs.back().get());
Brad Bishop68c80832016-11-29 16:41:32 -050087 }
Brad Bishop49aefb32016-10-19 11:54:14 -040088 }
89
90 _bus.request_name(busname);
Deepak Kodihallib28990f2017-08-08 07:19:34 -050091
92 // Restore any persistent inventory
93 restore();
Brad Bishop49aefb32016-10-19 11:54:14 -040094}
95
96void Manager::shutdown() noexcept
97{
98 _shutdown = true;
99}
100
101void Manager::run() noexcept
102{
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500103 sdbusplus::message::message unusedMsg{nullptr};
104
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 Bishop7b337772017-01-12 16:11:24 -0500117 while (!_shutdown)
118 {
119 try
120 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400121 _bus.process_discard();
Brad Bishop24424982017-01-13 16:37:14 -0500122 _bus.wait((5000000us).count());
Brad Bishop49aefb32016-10-19 11:54:14 -0400123 }
Brad Bishop7b337772017-01-12 16:11:24 -0500124 catch (const std::exception& e)
125 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400126 std::cerr << e.what() << std::endl;
127 }
128 }
129}
130
Brad Bishop615b2a82018-03-29 10:32:41 -0400131void Manager::updateInterfaces(const sdbusplus::message::object_path& path,
132 const Object& interfaces,
133 ObjectReferences::iterator pos, bool newObject,
134 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500135{
136 auto& refaces = pos->second;
137 auto ifaceit = interfaces.cbegin();
138 auto opsit = _makers.cbegin();
139 auto refaceit = refaces.begin();
140 std::vector<std::string> signals;
141
142 while (ifaceit != interfaces.cend())
143 {
144 try
145 {
146 // Find the binding ops for this interface.
Brad Bishop615b2a82018-03-29 10:32:41 -0400147 opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first,
148 compareFirst(_makers.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500149
150 if (opsit == _makers.cend() || opsit->first != ifaceit->first)
151 {
152 // This interface is not supported.
Brad Bishop615b2a82018-03-29 10:32:41 -0400153 throw InterfaceError("Encountered unsupported interface.",
154 ifaceit->first);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500155 }
156
157 // Find the binding insertion point or the binding to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400158 refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first,
159 compareFirst(refaces.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500160
161 if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
162 {
163 // Add the new interface.
Brad Bishop02763c62018-12-12 22:02:07 -0500164 auto& ctor = std::get<MakeInterfaceType>(opsit->second);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500165 refaceit = refaces.insert(
Brad Bishop615b2a82018-03-29 10:32:41 -0400166 refaceit,
167 std::make_pair(ifaceit->first, ctor(_bus, path.str.c_str(),
168 ifaceit->second)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500169 signals.push_back(ifaceit->first);
170 }
171 else
172 {
173 // Set the new property values.
Brad Bishop02763c62018-12-12 22:02:07 -0500174 auto& assign = std::get<AssignInterfaceType>(opsit->second);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500175 assign(ifaceit->second, refaceit->second);
176 }
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500177 if (!restoreFromCache)
178 {
Brad Bishop02763c62018-12-12 22:02:07 -0500179 auto& serialize =
180 std::get<SerializeInterfaceType<SerialOps>>(opsit->second);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500181 serialize(path, ifaceit->first, refaceit->second);
182 }
183 else
184 {
Brad Bishop02763c62018-12-12 22:02:07 -0500185 auto& deserialize =
186 std::get<DeserializeInterfaceType<SerialOps>>(
187 opsit->second);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500188 deserialize(path, ifaceit->first, refaceit->second);
189 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500190 }
191 catch (const InterfaceError& e)
192 {
193 // Reset the binding ops iterator since we are
194 // at the end.
195 opsit = _makers.cbegin();
196 e.log();
197 }
198
199 ++ifaceit;
200 }
201
202 if (newObject)
203 {
204 _bus.emit_object_added(path.str.c_str());
205 }
206 else if (!signals.empty())
207 {
Gunnar Millsa8ff8152017-06-06 12:54:28 -0500208 _bus.emit_interfaces_added(path.str.c_str(), signals);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500209 }
210}
211
212void Manager::updateObjects(
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500213 const std::map<sdbusplus::message::object_path, Object>& objs,
214 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500215{
216 auto objit = objs.cbegin();
217 auto refit = _refs.begin();
218 std::string absPath;
219 bool newObj;
220
221 while (objit != objs.cend())
222 {
223 // Find the insertion point or the object to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400224 refit = std::lower_bound(refit, _refs.end(), objit->first,
225 compareFirst(RelPathCompare(_root)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500226
227 absPath.assign(_root);
228 absPath.append(objit->first);
229
230 newObj = false;
231 if (refit == _refs.end() || refit->first != absPath)
232 {
233 refit = _refs.insert(
Brad Bishop615b2a82018-03-29 10:32:41 -0400234 refit, std::make_pair(absPath, decltype(_refs)::mapped_type()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500235 newObj = true;
236 }
237
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500238 updateInterfaces(absPath, objit->second, refit, newObj,
239 restoreFromCache);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500240 ++objit;
241 }
242}
243
Brad Bishop03f4cd92017-02-03 15:17:21 -0500244void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
Brad Bishop49aefb32016-10-19 11:54:14 -0400245{
Brad Bishopcda036f2017-02-15 10:06:48 -0500246 updateObjects(objs);
Brad Bishop49aefb32016-10-19 11:54:14 -0400247}
248
Brad Bishop615b2a82018-03-29 10:32:41 -0400249void Manager::handleEvent(sdbusplus::message::message& msg, const Event& event,
250 const EventInfo& info)
Brad Bishop49aefb32016-10-19 11:54:14 -0400251{
Brad Bishop7b337772017-01-12 16:11:24 -0500252 auto& actions = std::get<1>(info);
Brad Bishop3d57f502016-10-19 12:18:41 -0400253
Brad Bishop48547a82017-01-19 15:12:50 -0500254 for (auto& f : event)
Brad Bishop7b337772017-01-12 16:11:24 -0500255 {
Brad Bishop07934a62017-02-08 23:34:59 -0500256 if (!f(_bus, msg, *this))
Brad Bishop7b337772017-01-12 16:11:24 -0500257 {
Brad Bishop064c94a2017-01-21 21:33:30 -0500258 return;
Brad Bishop7b337772017-01-12 16:11:24 -0500259 }
Brad Bishop3d57f502016-10-19 12:18:41 -0400260 }
Brad Bishop064c94a2017-01-21 21:33:30 -0500261 for (auto& action : actions)
262 {
Brad Bishop07934a62017-02-08 23:34:59 -0500263 action(_bus, *this);
Brad Bishop064c94a2017-01-21 21:33:30 -0500264 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400265}
266
Brad Bishop615b2a82018-03-29 10:32:41 -0400267void Manager::destroyObjects(const std::vector<const char*>& paths)
Brad Bishop656a7d02016-10-19 22:20:02 -0400268{
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500269 std::string p;
270
Brad Bishop7b7e7122017-01-21 21:21:46 -0500271 for (const auto& path : paths)
272 {
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500273 p.assign(_root);
274 p.append(path);
275 _bus.emit_object_removed(p.c_str());
276 _refs.erase(p);
Brad Bishop7b7e7122017-01-21 21:21:46 -0500277 }
Brad Bishop656a7d02016-10-19 22:20:02 -0400278}
279
Brad Bishopeb68a682017-01-22 00:58:54 -0500280void Manager::createObjects(
281 const std::map<sdbusplus::message::object_path, Object>& objs)
282{
Brad Bishopcda036f2017-02-15 10:06:48 -0500283 updateObjects(objs);
Brad Bishopeb68a682017-01-22 00:58:54 -0500284}
285
Brad Bishop25d54b52018-11-21 12:57:51 -0500286std::any& Manager::getInterfaceHolder(const char* path, const char* interface)
Brad Bishopb83a21e2016-11-30 13:43:37 -0500287{
Brad Bishop25d54b52018-11-21 12:57:51 -0500288 return const_cast<std::any&>(
Brad Bishop615b2a82018-03-29 10:32:41 -0400289 const_cast<const Manager*>(this)->getInterfaceHolder(path, interface));
Brad Bishopb83a21e2016-11-30 13:43:37 -0500290}
291
Brad Bishop25d54b52018-11-21 12:57:51 -0500292const std::any& Manager::getInterfaceHolder(const char* path,
293 const char* interface) const
Brad Bishopb83a21e2016-11-30 13:43:37 -0500294{
295 std::string p{path};
296 auto oit = _refs.find(_root + p);
Brad Bishop7b337772017-01-12 16:11:24 -0500297 if (oit == _refs.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400298 throw std::runtime_error(_root + p + " was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500299
Brad Bishop7b337772017-01-12 16:11:24 -0500300 auto& obj = oit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500301 auto iit = obj.find(interface);
Brad Bishop7b337772017-01-12 16:11:24 -0500302 if (iit == obj.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400303 throw std::runtime_error("interface was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500304
Brad Bishop150147a2017-02-08 23:57:46 -0500305 return iit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500306}
307
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500308void Manager::restore()
309{
310 namespace fs = std::experimental::filesystem;
311
312 if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
313 {
314 return;
315 }
316
317 static const std::string remove =
318 std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
319
320 std::map<sdbusplus::message::object_path, Object> objects;
321 for (const auto& dirent :
322 fs::recursive_directory_iterator(PIM_PERSIST_PATH))
323 {
324 const auto& path = dirent.path();
325 if (fs::is_regular_file(path))
326 {
327 auto ifaceName = path.filename().string();
328 auto objPath = path.parent_path().string();
329 objPath.erase(0, remove.length());
330 auto objit = objects.find(objPath);
331 Interface propertyMap{};
332 if (objects.end() != objit)
333 {
334 auto& object = objit->second;
335 object.emplace(std::move(ifaceName), std::move(propertyMap));
336 }
337 else
338 {
339 Object object;
340 object.emplace(std::move(ifaceName), std::move(propertyMap));
341 objects.emplace(std::move(objPath), std::move(object));
342 }
343 }
344 }
345 if (!objects.empty())
346 {
347 auto restoreFromCache = true;
348 updateObjects(objects, restoreFromCache);
349 }
350}
351
Brad Bishop49aefb32016-10-19 11:54:14 -0400352} // namespace manager
353} // namespace inventory
354} // namespace phosphor
355
356// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4