blob: 8b35a0a76f2cdfc6904fe38f809050ded228df6c [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 Bishop615b2a82018-03-29 10:32:41 -040046 mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)),
47 *std::get<2>(args));
Brad Bishop49aefb32016-10-19 11:54:14 -040048 }
Brad Bishop7b337772017-01-12 16:11:24 -050049 catch (const std::exception& e)
50 {
Brad Bishop49aefb32016-10-19 11:54:14 -040051 std::cerr << e.what() << std::endl;
52 }
53
54 return 0;
55}
56
Brad Bishop615b2a82018-03-29 10:32:41 -040057Manager::Manager(sdbusplus::bus::bus&& bus, const char* busname,
58 const char* root, const char* iface) :
Brad Bishop12f8a3c2017-02-09 00:02:00 -050059 ServerObject<ManagerIface>(bus, root),
Brad Bishop615b2a82018-03-29 10:32:41 -040060 _shutdown(false), _root(root), _bus(std::move(bus)), _manager(_bus, root)
Brad Bishop49aefb32016-10-19 11:54:14 -040061{
Brad Bishop7b337772017-01-12 16:11:24 -050062 for (auto& group : _events)
Brad Bishop68c80832016-11-29 16:41:32 -050063 {
Brad Bishop615b2a82018-03-29 10:32:41 -040064 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop68c80832016-11-29 16:41:32 -050065 {
Brad Bishop615b2a82018-03-29 10:32:41 -040066 if (pEvent->type != Event::Type::DBUS_SIGNAL)
Brad Bishop7b337772017-01-12 16:11:24 -050067 {
Brad Bishop68c80832016-11-29 16:41:32 -050068 continue;
Brad Bishop7b337772017-01-12 16:11:24 -050069 }
Brad Bishop4f20a3e2016-11-29 15:21:46 -050070
Brad Bishop68c80832016-11-29 16:41:32 -050071 // Create a callback context for this event group.
Brad Bishop615b2a82018-03-29 10:32:41 -040072 auto dbusEvent = static_cast<DbusSignal*>(pEvent.get());
Brad Bishop68c80832016-11-29 16:41:32 -050073
74 // Go ahead and store an iterator pointing at
75 // the event data to avoid lookups later since
76 // additional signal callbacks aren't added
77 // after the manager is constructed.
78 _sigargs.emplace_back(
Brad Bishop615b2a82018-03-29 10:32:41 -040079 std::make_unique<SigArg>(this, dbusEvent, &group));
Brad Bishop68c80832016-11-29 16:41:32 -050080
81 // Register our callback and the context for
82 // each signal event.
Brad Bishop615b2a82018-03-29 10:32:41 -040083 _matches.emplace_back(_bus, dbusEvent->signature, _signal,
84 _sigargs.back().get());
Brad Bishop68c80832016-11-29 16:41:32 -050085 }
Brad Bishop49aefb32016-10-19 11:54:14 -040086 }
87
88 _bus.request_name(busname);
Deepak Kodihallib28990f2017-08-08 07:19:34 -050089
90 // Restore any persistent inventory
91 restore();
Brad Bishop49aefb32016-10-19 11:54:14 -040092}
93
94void Manager::shutdown() noexcept
95{
96 _shutdown = true;
97}
98
99void Manager::run() noexcept
100{
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500101 sdbusplus::message::message unusedMsg{nullptr};
102
103 // Run startup events.
104 for (auto& group : _events)
105 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400106 for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500107 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400108 if (pEvent->type == Event::Type::STARTUP)
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500109 {
110 handleEvent(unusedMsg, *pEvent, group);
111 }
112 }
113 }
114
Brad Bishop7b337772017-01-12 16:11:24 -0500115 while (!_shutdown)
116 {
117 try
118 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400119 _bus.process_discard();
Brad Bishop24424982017-01-13 16:37:14 -0500120 _bus.wait((5000000us).count());
Brad Bishop49aefb32016-10-19 11:54:14 -0400121 }
Brad Bishop7b337772017-01-12 16:11:24 -0500122 catch (const std::exception& e)
123 {
Brad Bishop49aefb32016-10-19 11:54:14 -0400124 std::cerr << e.what() << std::endl;
125 }
126 }
127}
128
Brad Bishop615b2a82018-03-29 10:32:41 -0400129void Manager::updateInterfaces(const sdbusplus::message::object_path& path,
130 const Object& interfaces,
131 ObjectReferences::iterator pos, bool newObject,
132 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500133{
134 auto& refaces = pos->second;
135 auto ifaceit = interfaces.cbegin();
136 auto opsit = _makers.cbegin();
137 auto refaceit = refaces.begin();
138 std::vector<std::string> signals;
139
140 while (ifaceit != interfaces.cend())
141 {
142 try
143 {
144 // Find the binding ops for this interface.
Brad Bishop615b2a82018-03-29 10:32:41 -0400145 opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first,
146 compareFirst(_makers.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500147
148 if (opsit == _makers.cend() || opsit->first != ifaceit->first)
149 {
150 // This interface is not supported.
Brad Bishop615b2a82018-03-29 10:32:41 -0400151 throw InterfaceError("Encountered unsupported interface.",
152 ifaceit->first);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500153 }
154
155 // Find the binding insertion point or the binding to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400156 refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first,
157 compareFirst(refaces.key_comp()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500158
159 if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
160 {
161 // Add the new interface.
162 auto& ctor = std::get<MakerType>(opsit->second);
163 refaceit = refaces.insert(
Brad Bishop615b2a82018-03-29 10:32:41 -0400164 refaceit,
165 std::make_pair(ifaceit->first, ctor(_bus, path.str.c_str(),
166 ifaceit->second)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500167 signals.push_back(ifaceit->first);
168 }
169 else
170 {
171 // Set the new property values.
172 auto& assign = std::get<AssignerType>(opsit->second);
173 assign(ifaceit->second, refaceit->second);
174 }
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500175 if (!restoreFromCache)
176 {
177 auto& serialize = std::get<SerializerType>(opsit->second);
178 serialize(path, ifaceit->first, refaceit->second);
179 }
180 else
181 {
182 auto& deserialize = std::get<DeserializerType>(opsit->second);
183 deserialize(path, ifaceit->first, refaceit->second);
184 }
Brad Bishop79ccaf72017-01-22 16:00:50 -0500185 }
186 catch (const InterfaceError& e)
187 {
188 // Reset the binding ops iterator since we are
189 // at the end.
190 opsit = _makers.cbegin();
191 e.log();
192 }
193
194 ++ifaceit;
195 }
196
197 if (newObject)
198 {
199 _bus.emit_object_added(path.str.c_str());
200 }
201 else if (!signals.empty())
202 {
Gunnar Millsa8ff8152017-06-06 12:54:28 -0500203 _bus.emit_interfaces_added(path.str.c_str(), signals);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500204 }
205}
206
207void Manager::updateObjects(
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500208 const std::map<sdbusplus::message::object_path, Object>& objs,
209 bool restoreFromCache)
Brad Bishop79ccaf72017-01-22 16:00:50 -0500210{
211 auto objit = objs.cbegin();
212 auto refit = _refs.begin();
213 std::string absPath;
214 bool newObj;
215
216 while (objit != objs.cend())
217 {
218 // Find the insertion point or the object to update.
Brad Bishop615b2a82018-03-29 10:32:41 -0400219 refit = std::lower_bound(refit, _refs.end(), objit->first,
220 compareFirst(RelPathCompare(_root)));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500221
222 absPath.assign(_root);
223 absPath.append(objit->first);
224
225 newObj = false;
226 if (refit == _refs.end() || refit->first != absPath)
227 {
228 refit = _refs.insert(
Brad Bishop615b2a82018-03-29 10:32:41 -0400229 refit, std::make_pair(absPath, decltype(_refs)::mapped_type()));
Brad Bishop79ccaf72017-01-22 16:00:50 -0500230 newObj = true;
231 }
232
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500233 updateInterfaces(absPath, objit->second, refit, newObj,
234 restoreFromCache);
Brad Bishop79ccaf72017-01-22 16:00:50 -0500235 ++objit;
236 }
237}
238
Brad Bishop03f4cd92017-02-03 15:17:21 -0500239void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
Brad Bishop49aefb32016-10-19 11:54:14 -0400240{
Brad Bishopcda036f2017-02-15 10:06:48 -0500241 updateObjects(objs);
Brad Bishop49aefb32016-10-19 11:54:14 -0400242}
243
Brad Bishop615b2a82018-03-29 10:32:41 -0400244void Manager::handleEvent(sdbusplus::message::message& msg, const Event& event,
245 const EventInfo& info)
Brad Bishop49aefb32016-10-19 11:54:14 -0400246{
Brad Bishop7b337772017-01-12 16:11:24 -0500247 auto& actions = std::get<1>(info);
Brad Bishop3d57f502016-10-19 12:18:41 -0400248
Brad Bishop48547a82017-01-19 15:12:50 -0500249 for (auto& f : event)
Brad Bishop7b337772017-01-12 16:11:24 -0500250 {
Brad Bishop07934a62017-02-08 23:34:59 -0500251 if (!f(_bus, msg, *this))
Brad Bishop7b337772017-01-12 16:11:24 -0500252 {
Brad Bishop064c94a2017-01-21 21:33:30 -0500253 return;
Brad Bishop7b337772017-01-12 16:11:24 -0500254 }
Brad Bishop3d57f502016-10-19 12:18:41 -0400255 }
Brad Bishop064c94a2017-01-21 21:33:30 -0500256 for (auto& action : actions)
257 {
Brad Bishop07934a62017-02-08 23:34:59 -0500258 action(_bus, *this);
Brad Bishop064c94a2017-01-21 21:33:30 -0500259 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400260}
261
Brad Bishop615b2a82018-03-29 10:32:41 -0400262void Manager::destroyObjects(const std::vector<const char*>& paths)
Brad Bishop656a7d02016-10-19 22:20:02 -0400263{
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500264 std::string p;
265
Brad Bishop7b7e7122017-01-21 21:21:46 -0500266 for (const auto& path : paths)
267 {
Brad Bishopa5cc34c2017-02-03 20:57:36 -0500268 p.assign(_root);
269 p.append(path);
270 _bus.emit_object_removed(p.c_str());
271 _refs.erase(p);
Brad Bishop7b7e7122017-01-21 21:21:46 -0500272 }
Brad Bishop656a7d02016-10-19 22:20:02 -0400273}
274
Brad Bishopeb68a682017-01-22 00:58:54 -0500275void Manager::createObjects(
276 const std::map<sdbusplus::message::object_path, Object>& objs)
277{
Brad Bishopcda036f2017-02-15 10:06:48 -0500278 updateObjects(objs);
Brad Bishopeb68a682017-01-22 00:58:54 -0500279}
280
Brad Bishop615b2a82018-03-29 10:32:41 -0400281any_ns::any& Manager::getInterfaceHolder(const char* path,
282 const char* interface)
Brad Bishopb83a21e2016-11-30 13:43:37 -0500283{
Brad Bishop150147a2017-02-08 23:57:46 -0500284 return const_cast<any_ns::any&>(
Brad Bishop615b2a82018-03-29 10:32:41 -0400285 const_cast<const Manager*>(this)->getInterfaceHolder(path, interface));
Brad Bishopb83a21e2016-11-30 13:43:37 -0500286}
287
Brad Bishop615b2a82018-03-29 10:32:41 -0400288const any_ns::any& Manager::getInterfaceHolder(const char* path,
289 const char* interface) const
Brad Bishopb83a21e2016-11-30 13:43:37 -0500290{
291 std::string p{path};
292 auto oit = _refs.find(_root + p);
Brad Bishop7b337772017-01-12 16:11:24 -0500293 if (oit == _refs.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400294 throw std::runtime_error(_root + p + " was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500295
Brad Bishop7b337772017-01-12 16:11:24 -0500296 auto& obj = oit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500297 auto iit = obj.find(interface);
Brad Bishop7b337772017-01-12 16:11:24 -0500298 if (iit == obj.end())
Brad Bishop615b2a82018-03-29 10:32:41 -0400299 throw std::runtime_error("interface was not found");
Brad Bishopb83a21e2016-11-30 13:43:37 -0500300
Brad Bishop150147a2017-02-08 23:57:46 -0500301 return iit->second;
Brad Bishopb83a21e2016-11-30 13:43:37 -0500302}
303
Deepak Kodihallib28990f2017-08-08 07:19:34 -0500304void Manager::restore()
305{
306 namespace fs = std::experimental::filesystem;
307
308 if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
309 {
310 return;
311 }
312
313 static const std::string remove =
314 std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
315
316 std::map<sdbusplus::message::object_path, Object> objects;
317 for (const auto& dirent :
318 fs::recursive_directory_iterator(PIM_PERSIST_PATH))
319 {
320 const auto& path = dirent.path();
321 if (fs::is_regular_file(path))
322 {
323 auto ifaceName = path.filename().string();
324 auto objPath = path.parent_path().string();
325 objPath.erase(0, remove.length());
326 auto objit = objects.find(objPath);
327 Interface propertyMap{};
328 if (objects.end() != objit)
329 {
330 auto& object = objit->second;
331 object.emplace(std::move(ifaceName), std::move(propertyMap));
332 }
333 else
334 {
335 Object object;
336 object.emplace(std::move(ifaceName), std::move(propertyMap));
337 objects.emplace(std::move(objPath), std::move(object));
338 }
339 }
340 }
341 if (!objects.empty())
342 {
343 auto restoreFromCache = true;
344 updateObjects(objects, restoreFromCache);
345 }
346}
347
Brad Bishop49aefb32016-10-19 11:54:14 -0400348} // namespace manager
349} // namespace inventory
350} // namespace phosphor
351
352// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4