blob: 6049161ccc733248be5773a7bf32f2b621112c45 [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 */
16#include <iostream>
17#include <exception>
Brad Bishop24424982017-01-13 16:37:14 -050018#include <chrono>
Brad Bishop79ccaf72017-01-22 16:00:50 -050019#include <algorithm>
Saqib Khan101d8372017-02-20 15:36:11 -060020#include <phosphor-logging/log.hpp>
Deepak Kodihallib28990f2017-08-08 07:19:34 -050021#include <experimental/filesystem>
Brad Bishop49aefb32016-10-19 11:54:14 -040022#include "manager.hpp"
Brad Bishop79ccaf72017-01-22 16:00:50 -050023#include "errors.hpp"
Brad Bishop49aefb32016-10-19 11:54:14 -040024
Brad Bishop24424982017-01-13 16:37:14 -050025using namespace std::literals::chrono_literals;
26
Brad Bishop49aefb32016-10-19 11:54:14 -040027namespace phosphor
28{
29namespace inventory
30{
31namespace manager
32{
Brad Bishop49aefb32016-10-19 11:54:14 -040033/** @brief Fowrarding signal callback.
34 *
35 * Extracts per-signal specific context and forwards the call to the manager
36 * instance.
37 */
Brad Bishop7b337772017-01-12 16:11:24 -050038auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
Brad Bishop49aefb32016-10-19 11:54:14 -040039{
Brad Bishop7b337772017-01-12 16:11:24 -050040 try
41 {
Brad Bishop49aefb32016-10-19 11:54:14 -040042 auto msg = sdbusplus::message::message(m);
Brad Bishop7b337772017-01-12 16:11:24 -050043 auto& args = *static_cast<Manager::SigArg*>(data);
Brad Bishop49aefb32016-10-19 11:54:14 -040044 sd_bus_message_ref(m);
Brad Bishop7b337772017-01-12 16:11:24 -050045 auto& mgr = *std::get<0>(args);
Brad Bishop48547a82017-01-19 15:12:50 -050046 mgr.handleEvent(
Brad Bishop7b337772017-01-12 16:11:24 -050047 msg,
Brad Bishop12f8a3c2017-02-09 00:02:00 -050048 static_cast<const DbusSignal&>(
Brad Bishop7b337772017-01-12 16:11:24 -050049 *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 Bishop49aefb32016-10-19 11:54:14 -040060Manager::Manager(
Brad Bishop7b337772017-01-12 16:11:24 -050061 sdbusplus::bus::bus&& bus,
62 const char* busname,
63 const char* root,
64 const char* iface) :
Brad Bishop12f8a3c2017-02-09 00:02:00 -050065 ServerObject<ManagerIface>(bus, root),
Brad Bishop49aefb32016-10-19 11:54:14 -040066 _shutdown(false),
67 _root(root),
68 _bus(std::move(bus)),
Brad Bishop9b864832017-03-07 00:10:33 -050069 _manager(_bus, root)
Brad Bishop49aefb32016-10-19 11:54:14 -040070{
Brad Bishop7b337772017-01-12 16:11:24 -050071 for (auto& group : _events)
Brad Bishop68c80832016-11-29 16:41:32 -050072 {
Brad Bishop12f8a3c2017-02-09 00:02:00 -050073 for (auto pEvent : std::get<std::vector<EventBasePtr>>(
Brad Bishop48547a82017-01-19 15:12:50 -050074 group))
Brad Bishop68c80832016-11-29 16:41:32 -050075 {
76 if (pEvent->type !=
Brad Bishop12f8a3c2017-02-09 00:02:00 -050077 Event::Type::DBUS_SIGNAL)
Brad Bishop7b337772017-01-12 16:11:24 -050078 {
Brad Bishop68c80832016-11-29 16:41:32 -050079 continue;
Brad Bishop7b337772017-01-12 16:11:24 -050080 }
Brad Bishop4f20a3e2016-11-29 15:21:46 -050081
Brad Bishop68c80832016-11-29 16:41:32 -050082 // Create a callback context for this event group.
Brad Bishop12f8a3c2017-02-09 00:02:00 -050083 auto dbusEvent = static_cast<DbusSignal*>(
Brad Bishop7b337772017-01-12 16:11:24 -050084 pEvent.get());
Brad Bishop68c80832016-11-29 16:41:32 -050085
86 // Go ahead and store an iterator pointing at
87 // the event data to avoid lookups later since
88 // additional signal callbacks aren't added
89 // after the manager is constructed.
90 _sigargs.emplace_back(
Brad Bishop7b337772017-01-12 16:11:24 -050091 std::make_unique<SigArg>(
92 this,
93 dbusEvent,
94 &group));
Brad Bishop68c80832016-11-29 16:41:32 -050095
96 // Register our callback and the context for
97 // each signal event.
98 _matches.emplace_back(
Brad Bishop7b337772017-01-12 16:11:24 -050099 _bus,
Brad Bishop48547a82017-01-19 15:12:50 -0500100 dbusEvent->signature,
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500101 _signal,
Brad Bishop7b337772017-01-12 16:11:24 -0500102 _sigargs.back().get());
Brad Bishop68c80832016-11-29 16:41:32 -0500103 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400104 }
105
106 _bus.request_name(busname);
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500107
108 // Restore any persistent inventory
109 restore();
Brad Bishop49aefb32016-10-19 11:54:14 -0400110}
111
112void Manager::shutdown() noexcept
113{
114 _shutdown = true;
115}
116
117void Manager::run() noexcept
118{
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500119 sdbusplus::message::message unusedMsg{nullptr};
120
121 // Run startup events.
122 for (auto& group : _events)
123 {
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500124 for (auto pEvent : std::get<std::vector<EventBasePtr>>(
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500125 group))
126 {
127 if (pEvent->type ==
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500128 Event::Type::STARTUP)
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500129 {
130 handleEvent(unusedMsg, *pEvent, group);
131 }
132 }
133 }
134
Brad Bishop7b337772017-01-12 16:11:24 -0500135 while (!_shutdown)
136 {
137 try
138 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400139 _bus.process_discard();
Brad Bishop24424982017-01-13 16:37:14 -0500140 _bus.wait((5000000us).count());
Brad Bishop49aefb32016-10-19 11:54:14 -0400141 }
Brad Bishop7b337772017-01-12 16:11:24 -0500142 catch (const std::exception& e)
143 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400144 std::cerr << e.what() << std::endl;
145 }
146 }
147}
148
Brad Bishop79ccaf72017-01-22 16:00:50 -0500149void Manager::updateInterfaces(
150 const sdbusplus::message::object_path& path,
151 const Object& interfaces,
152 ObjectReferences::iterator pos,
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500153 bool newObject,
154 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500155{
156 auto& refaces = pos->second;
157 auto ifaceit = interfaces.cbegin();
158 auto opsit = _makers.cbegin();
159 auto refaceit = refaces.begin();
160 std::vector<std::string> signals;
161
162 while (ifaceit != interfaces.cend())
163 {
164 try
165 {
166 // Find the binding ops for this interface.
167 opsit = std::lower_bound(
168 opsit,
169 _makers.cend(),
170 ifaceit->first,
171 compareFirst(_makers.key_comp()));
172
173 if (opsit == _makers.cend() || opsit->first != ifaceit->first)
174 {
175 // This interface is not supported.
176 throw InterfaceError(
177 "Encountered unsupported interface.",
178 ifaceit->first);
179 }
180
181 // Find the binding insertion point or the binding to update.
182 refaceit = std::lower_bound(
183 refaceit,
184 refaces.end(),
185 ifaceit->first,
186 compareFirst(refaces.key_comp()));
187
188 if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
189 {
190 // Add the new interface.
191 auto& ctor = std::get<MakerType>(opsit->second);
192 refaceit = refaces.insert(
193 refaceit,
194 std::make_pair(
195 ifaceit->first,
196 ctor(
197 _bus,
198 path.str.c_str(),
199 ifaceit->second)));
200 signals.push_back(ifaceit->first);
201 }
202 else
203 {
204 // Set the new property values.
205 auto& assign = std::get<AssignerType>(opsit->second);
206 assign(ifaceit->second, refaceit->second);
207 }
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500208 if (!restoreFromCache)
209 {
210 auto& serialize = std::get<SerializerType>(opsit->second);
211 serialize(path, ifaceit->first, refaceit->second);
212 }
213 else
214 {
215 auto& deserialize = std::get<DeserializerType>(opsit->second);
216 deserialize(path, ifaceit->first, refaceit->second);
217 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500218 }
219 catch (const InterfaceError& e)
220 {
221 // Reset the binding ops iterator since we are
222 // at the end.
223 opsit = _makers.cbegin();
224 e.log();
225 }
226
227 ++ifaceit;
228 }
229
230 if (newObject)
231 {
232 _bus.emit_object_added(path.str.c_str());
233 }
234 else if (!signals.empty())
235 {
Gunnar Millsa8ff8152017-06-06 12:54:28 -0500236 _bus.emit_interfaces_added(path.str.c_str(), signals);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500237 }
238}
239
240void Manager::updateObjects(
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500241 const std::map<sdbusplus::message::object_path, Object>& objs,
242 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500243{
244 auto objit = objs.cbegin();
245 auto refit = _refs.begin();
246 std::string absPath;
247 bool newObj;
248
249 while (objit != objs.cend())
250 {
251 // Find the insertion point or the object to update.
252 refit = std::lower_bound(
253 refit,
254 _refs.end(),
255 objit->first,
256 compareFirst(RelPathCompare(_root)));
257
258 absPath.assign(_root);
259 absPath.append(objit->first);
260
261 newObj = false;
262 if (refit == _refs.end() || refit->first != absPath)
263 {
264 refit = _refs.insert(
265 refit,
266 std::make_pair(
267 absPath,
268 decltype(_refs)::mapped_type()));
269 newObj = true;
270 }
271
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500272 updateInterfaces(absPath, objit->second, refit, newObj,
273 restoreFromCache);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500274 ++objit;
275 }
276}
277
Brad Bishop03f4cd92017-02-03 15:17:21 -0500278void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
Brad Bishop49aefb32016-10-19 11:54:14 -0400279{
Brad Bishopcda036f2017-02-15 10:06:48 -0500280 updateObjects(objs);
Brad Bishop49aefb32016-10-19 11:54:14 -0400281}
282
Brad Bishop48547a82017-01-19 15:12:50 -0500283void Manager::handleEvent(
Brad Bishop7b337772017-01-12 16:11:24 -0500284 sdbusplus::message::message& msg,
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500285 const Event& event,
Brad Bishop7b337772017-01-12 16:11:24 -0500286 const EventInfo& info)
Brad Bishop49aefb32016-10-19 11:54:14 -0400287{
Brad Bishop7b337772017-01-12 16:11:24 -0500288 auto& actions = std::get<1>(info);
Brad Bishop3d57f502016-10-19 12:18:41 -0400289
Brad Bishop48547a82017-01-19 15:12:50 -0500290 for (auto& f : event)
Brad Bishop7b337772017-01-12 16:11:24 -0500291 {
Brad Bishop07934a62017-02-08 23:34:59 -0500292 if (!f(_bus, msg, *this))
Brad Bishop7b337772017-01-12 16:11:24 -0500293 {
Brad Bishop064c94a2017-01-21 21:33:30 -0500294 return;
Brad Bishop7b337772017-01-12 16:11:24 -0500295 }
Brad Bishop3d57f502016-10-19 12:18:41 -0400296 }
Brad Bishop064c94a2017-01-21 21:33:30 -0500297 for (auto& action : actions)
298 {
Brad Bishop07934a62017-02-08 23:34:59 -0500299 action(_bus, *this);
Brad Bishop064c94a2017-01-21 21:33:30 -0500300 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400301}
302
Brad Bishop7b7e7122017-01-21 21:21:46 -0500303void Manager::destroyObjects(
304 const std::vector<const char*>& paths)
Brad Bishop656a7d02016-10-19 22:20:02 -0400305{
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500306 std::string p;
307
Brad Bishop7b7e7122017-01-21 21:21:46 -0500308 for (const auto& path : paths)
309 {
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500310 p.assign(_root);
311 p.append(path);
312 _bus.emit_object_removed(p.c_str());
313 _refs.erase(p);
Brad Bishop7b7e7122017-01-21 21:21:46 -0500314 }
Brad Bishop656a7d02016-10-19 22:20:02 -0400315}
316
Brad Bishopeb68a682017-01-22 00:58:54 -0500317void Manager::createObjects(
318 const std::map<sdbusplus::message::object_path, Object>& objs)
319{
Brad Bishopcda036f2017-02-15 10:06:48 -0500320 updateObjects(objs);
Brad Bishopeb68a682017-01-22 00:58:54 -0500321}
322
Brad Bishop150147a2017-02-08 23:57:46 -0500323any_ns::any& Manager::getInterfaceHolder(
Brad Bishop7b337772017-01-12 16:11:24 -0500324 const char* path, const char* interface)
Brad Bishopb83a21e2016-11-30 13:43:37 -0500325{
Brad Bishop150147a2017-02-08 23:57:46 -0500326 return const_cast<any_ns::any&>(
327 const_cast<const Manager*>(
328 this)->getInterfaceHolder(path, interface));
Brad Bishopb83a21e2016-11-30 13:43:37 -0500329}
330
Brad Bishop150147a2017-02-08 23:57:46 -0500331const any_ns::any& Manager::getInterfaceHolder(
Brad Bishop7b337772017-01-12 16:11:24 -0500332 const char* path, const char* interface) const
Brad Bishopb83a21e2016-11-30 13:43:37 -0500333{
334 std::string p{path};
335 auto oit = _refs.find(_root + p);
Brad Bishop7b337772017-01-12 16:11:24 -0500336 if (oit == _refs.end())
Brad Bishopb83a21e2016-11-30 13:43:37 -0500337 throw std::runtime_error(
Brad Bishop7b337772017-01-12 16:11:24 -0500338 _root + p + " was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500339
Brad Bishop7b337772017-01-12 16:11:24 -0500340 auto& obj = oit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500341 auto iit = obj.find(interface);
Brad Bishop7b337772017-01-12 16:11:24 -0500342 if (iit == obj.end())
Brad Bishopb83a21e2016-11-30 13:43:37 -0500343 throw std::runtime_error(
Brad Bishop7b337772017-01-12 16:11:24 -0500344 "interface was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500345
Brad Bishop150147a2017-02-08 23:57:46 -0500346 return iit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500347}
348
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500349void Manager::restore()
350{
351 namespace fs = std::experimental::filesystem;
352
353 if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
354 {
355 return;
356 }
357
358 static const std::string remove =
359 std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
360
361 std::map<sdbusplus::message::object_path, Object> objects;
362 for (const auto& dirent :
363 fs::recursive_directory_iterator(PIM_PERSIST_PATH))
364 {
365 const auto& path = dirent.path();
366 if (fs::is_regular_file(path))
367 {
368 auto ifaceName = path.filename().string();
369 auto objPath = path.parent_path().string();
370 objPath.erase(0, remove.length());
371 auto objit = objects.find(objPath);
372 Interface propertyMap{};
373 if (objects.end() != objit)
374 {
375 auto& object = objit->second;
376 object.emplace(std::move(ifaceName), std::move(propertyMap));
377 }
378 else
379 {
380 Object object;
381 object.emplace(std::move(ifaceName), std::move(propertyMap));
382 objects.emplace(std::move(objPath), std::move(object));
383 }
384 }
385 }
386 if (!objects.empty())
387 {
388 auto restoreFromCache = true;
389 updateObjects(objects, restoreFromCache);
390 }
391}
392
Brad Bishop49aefb32016-10-19 11:54:14 -0400393} // namespace manager
394} // namespace inventory
395} // namespace phosphor
396
397// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4