149aefb31SBrad Bishop /**
249aefb31SBrad Bishop  * Copyright © 2016 IBM Corporation
349aefb31SBrad Bishop  *
449aefb31SBrad Bishop  * Licensed under the Apache License, Version 2.0 (the "License");
549aefb31SBrad Bishop  * you may not use this file except in compliance with the License.
649aefb31SBrad Bishop  * You may obtain a copy of the License at
749aefb31SBrad Bishop  *
849aefb31SBrad Bishop  *     http://www.apache.org/licenses/LICENSE-2.0
949aefb31SBrad Bishop  *
1049aefb31SBrad Bishop  * Unless required by applicable law or agreed to in writing, software
1149aefb31SBrad Bishop  * distributed under the License is distributed on an "AS IS" BASIS,
1249aefb31SBrad Bishop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349aefb31SBrad Bishop  * See the License for the specific language governing permissions and
1449aefb31SBrad Bishop  * limitations under the License.
1549aefb31SBrad Bishop  */
1649aefb31SBrad Bishop #include <iostream>
1749aefb31SBrad Bishop #include <exception>
1824424983SBrad Bishop #include <chrono>
1979ccaf77SBrad Bishop #include <algorithm>
20101d837cSSaqib Khan #include <phosphor-logging/log.hpp>
21b28990f3SDeepak Kodihalli #include <experimental/filesystem>
2249aefb31SBrad Bishop #include "manager.hpp"
2379ccaf77SBrad Bishop #include "errors.hpp"
2449aefb31SBrad Bishop 
2524424983SBrad Bishop using namespace std::literals::chrono_literals;
2624424983SBrad Bishop 
2749aefb31SBrad Bishop namespace phosphor
2849aefb31SBrad Bishop {
2949aefb31SBrad Bishop namespace inventory
3049aefb31SBrad Bishop {
3149aefb31SBrad Bishop namespace manager
3249aefb31SBrad Bishop {
3349aefb31SBrad Bishop /** @brief Fowrarding signal callback.
3449aefb31SBrad Bishop  *
3549aefb31SBrad Bishop  *  Extracts per-signal specific context and forwards the call to the manager
3649aefb31SBrad Bishop  *  instance.
3749aefb31SBrad Bishop  */
3849aefb31SBrad Bishop auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
3949aefb31SBrad Bishop {
407b33777bSBrad Bishop     try
417b33777bSBrad Bishop     {
4249aefb31SBrad Bishop         auto msg = sdbusplus::message::message(m);
4349aefb31SBrad Bishop         auto& args = *static_cast<Manager::SigArg*>(data);
4449aefb31SBrad Bishop         sd_bus_message_ref(m);
4549aefb31SBrad Bishop         auto& mgr = *std::get<0>(args);
46*615b2a8fSBrad Bishop         mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)),
4768c80839SBrad Bishop                         *std::get<2>(args));
4849aefb31SBrad Bishop     }
497b33777bSBrad Bishop     catch (const std::exception& e)
507b33777bSBrad Bishop     {
5149aefb31SBrad Bishop         std::cerr << e.what() << std::endl;
5249aefb31SBrad Bishop     }
5349aefb31SBrad Bishop 
5449aefb31SBrad Bishop     return 0;
5549aefb31SBrad Bishop }
5649aefb31SBrad Bishop 
57*615b2a8fSBrad Bishop Manager::Manager(sdbusplus::bus::bus&& bus, const char* busname,
58*615b2a8fSBrad Bishop                  const char* root, const char* iface) :
5912f8a3c8SBrad Bishop     ServerObject<ManagerIface>(bus, root),
60*615b2a8fSBrad Bishop     _shutdown(false), _root(root), _bus(std::move(bus)), _manager(_bus, root)
6149aefb31SBrad Bishop {
6268c80839SBrad Bishop     for (auto& group : _events)
6368c80839SBrad Bishop     {
64*615b2a8fSBrad Bishop         for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
6568c80839SBrad Bishop         {
66*615b2a8fSBrad Bishop             if (pEvent->type != Event::Type::DBUS_SIGNAL)
677b33777bSBrad Bishop             {
684f20a3e3SBrad Bishop                 continue;
697b33777bSBrad Bishop             }
704f20a3e3SBrad Bishop 
7168c80839SBrad Bishop             // Create a callback context for this event group.
72*615b2a8fSBrad Bishop             auto dbusEvent = static_cast<DbusSignal*>(pEvent.get());
7368c80839SBrad Bishop 
7468c80839SBrad Bishop             // Go ahead and store an iterator pointing at
7568c80839SBrad Bishop             // the event data to avoid lookups later since
7668c80839SBrad Bishop             // additional signal callbacks aren't added
7768c80839SBrad Bishop             // after the manager is constructed.
7849aefb31SBrad Bishop             _sigargs.emplace_back(
79*615b2a8fSBrad Bishop                 std::make_unique<SigArg>(this, dbusEvent, &group));
8068c80839SBrad Bishop 
8149aefb31SBrad Bishop             // Register our callback and the context for
8268c80839SBrad Bishop             // each signal event.
83*615b2a8fSBrad Bishop             _matches.emplace_back(_bus, dbusEvent->signature, _signal,
841ab880a1SBrad Bishop                                   _sigargs.back().get());
8549aefb31SBrad Bishop         }
8668c80839SBrad Bishop     }
8749aefb31SBrad Bishop 
8849aefb31SBrad Bishop     _bus.request_name(busname);
89b28990f3SDeepak Kodihalli 
90b28990f3SDeepak Kodihalli     // Restore any persistent inventory
91b28990f3SDeepak Kodihalli     restore();
9249aefb31SBrad Bishop }
9349aefb31SBrad Bishop 
9449aefb31SBrad Bishop void Manager::shutdown() noexcept
9549aefb31SBrad Bishop {
9649aefb31SBrad Bishop     _shutdown = true;
9749aefb31SBrad Bishop }
9849aefb31SBrad Bishop 
9949aefb31SBrad Bishop void Manager::run() noexcept
10049aefb31SBrad Bishop {
1013e4a19a3SBrad Bishop     sdbusplus::message::message unusedMsg{nullptr};
1023e4a19a3SBrad Bishop 
1033e4a19a3SBrad Bishop     // Run startup events.
1043e4a19a3SBrad Bishop     for (auto& group : _events)
1053e4a19a3SBrad Bishop     {
106*615b2a8fSBrad Bishop         for (auto pEvent : std::get<std::vector<EventBasePtr>>(group))
1073e4a19a3SBrad Bishop         {
108*615b2a8fSBrad Bishop             if (pEvent->type == Event::Type::STARTUP)
1093e4a19a3SBrad Bishop             {
1103e4a19a3SBrad Bishop                 handleEvent(unusedMsg, *pEvent, group);
1113e4a19a3SBrad Bishop             }
1123e4a19a3SBrad Bishop         }
1133e4a19a3SBrad Bishop     }
1143e4a19a3SBrad Bishop 
1157b33777bSBrad Bishop     while (!_shutdown)
1167b33777bSBrad Bishop     {
1177b33777bSBrad Bishop         try
1187b33777bSBrad Bishop         {
11949aefb31SBrad Bishop             _bus.process_discard();
12024424983SBrad Bishop             _bus.wait((5000000us).count());
12149aefb31SBrad Bishop         }
1227b33777bSBrad Bishop         catch (const std::exception& e)
1237b33777bSBrad Bishop         {
12449aefb31SBrad Bishop             std::cerr << e.what() << std::endl;
12549aefb31SBrad Bishop         }
12649aefb31SBrad Bishop     }
12749aefb31SBrad Bishop }
12849aefb31SBrad Bishop 
129*615b2a8fSBrad Bishop void Manager::updateInterfaces(const sdbusplus::message::object_path& path,
13079ccaf77SBrad Bishop                                const Object& interfaces,
131*615b2a8fSBrad Bishop                                ObjectReferences::iterator pos, bool newObject,
132b28990f3SDeepak Kodihalli                                bool restoreFromCache)
13379ccaf77SBrad Bishop {
13479ccaf77SBrad Bishop     auto& refaces = pos->second;
13579ccaf77SBrad Bishop     auto ifaceit = interfaces.cbegin();
13679ccaf77SBrad Bishop     auto opsit = _makers.cbegin();
13779ccaf77SBrad Bishop     auto refaceit = refaces.begin();
13879ccaf77SBrad Bishop     std::vector<std::string> signals;
13979ccaf77SBrad Bishop 
14079ccaf77SBrad Bishop     while (ifaceit != interfaces.cend())
14179ccaf77SBrad Bishop     {
14279ccaf77SBrad Bishop         try
14379ccaf77SBrad Bishop         {
14479ccaf77SBrad Bishop             // Find the binding ops for this interface.
145*615b2a8fSBrad Bishop             opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first,
14679ccaf77SBrad Bishop                                      compareFirst(_makers.key_comp()));
14779ccaf77SBrad Bishop 
14879ccaf77SBrad Bishop             if (opsit == _makers.cend() || opsit->first != ifaceit->first)
14979ccaf77SBrad Bishop             {
15079ccaf77SBrad Bishop                 // This interface is not supported.
151*615b2a8fSBrad Bishop                 throw InterfaceError("Encountered unsupported interface.",
15279ccaf77SBrad Bishop                                      ifaceit->first);
15379ccaf77SBrad Bishop             }
15479ccaf77SBrad Bishop 
15579ccaf77SBrad Bishop             // Find the binding insertion point or the binding to update.
156*615b2a8fSBrad Bishop             refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first,
15779ccaf77SBrad Bishop                                         compareFirst(refaces.key_comp()));
15879ccaf77SBrad Bishop 
15979ccaf77SBrad Bishop             if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
16079ccaf77SBrad Bishop             {
16179ccaf77SBrad Bishop                 // Add the new interface.
16279ccaf77SBrad Bishop                 auto& ctor = std::get<MakerType>(opsit->second);
16379ccaf77SBrad Bishop                 refaceit = refaces.insert(
16479ccaf77SBrad Bishop                     refaceit,
165*615b2a8fSBrad Bishop                     std::make_pair(ifaceit->first, ctor(_bus, path.str.c_str(),
16679ccaf77SBrad Bishop                                                         ifaceit->second)));
16779ccaf77SBrad Bishop                 signals.push_back(ifaceit->first);
16879ccaf77SBrad Bishop             }
16979ccaf77SBrad Bishop             else
17079ccaf77SBrad Bishop             {
17179ccaf77SBrad Bishop                 // Set the new property values.
17279ccaf77SBrad Bishop                 auto& assign = std::get<AssignerType>(opsit->second);
17379ccaf77SBrad Bishop                 assign(ifaceit->second, refaceit->second);
17479ccaf77SBrad Bishop             }
175b28990f3SDeepak Kodihalli             if (!restoreFromCache)
176b28990f3SDeepak Kodihalli             {
1776620e98dSDeepak Kodihalli                 auto& serialize = std::get<SerializerType>(opsit->second);
1786620e98dSDeepak Kodihalli                 serialize(path, ifaceit->first, refaceit->second);
17979ccaf77SBrad Bishop             }
180b28990f3SDeepak Kodihalli             else
181b28990f3SDeepak Kodihalli             {
182b28990f3SDeepak Kodihalli                 auto& deserialize = std::get<DeserializerType>(opsit->second);
183b28990f3SDeepak Kodihalli                 deserialize(path, ifaceit->first, refaceit->second);
184b28990f3SDeepak Kodihalli             }
185b28990f3SDeepak Kodihalli         }
18679ccaf77SBrad Bishop         catch (const InterfaceError& e)
18779ccaf77SBrad Bishop         {
18879ccaf77SBrad Bishop             // Reset the binding ops iterator since we are
18979ccaf77SBrad Bishop             // at the end.
19079ccaf77SBrad Bishop             opsit = _makers.cbegin();
19179ccaf77SBrad Bishop             e.log();
19279ccaf77SBrad Bishop         }
19379ccaf77SBrad Bishop 
19479ccaf77SBrad Bishop         ++ifaceit;
19579ccaf77SBrad Bishop     }
19679ccaf77SBrad Bishop 
19779ccaf77SBrad Bishop     if (newObject)
19879ccaf77SBrad Bishop     {
19979ccaf77SBrad Bishop         _bus.emit_object_added(path.str.c_str());
20079ccaf77SBrad Bishop     }
20179ccaf77SBrad Bishop     else if (!signals.empty())
20279ccaf77SBrad Bishop     {
203a8ff8154SGunnar Mills         _bus.emit_interfaces_added(path.str.c_str(), signals);
20479ccaf77SBrad Bishop     }
20579ccaf77SBrad Bishop }
20679ccaf77SBrad Bishop 
20779ccaf77SBrad Bishop void Manager::updateObjects(
208b28990f3SDeepak Kodihalli     const std::map<sdbusplus::message::object_path, Object>& objs,
209b28990f3SDeepak Kodihalli     bool restoreFromCache)
21079ccaf77SBrad Bishop {
21179ccaf77SBrad Bishop     auto objit = objs.cbegin();
21279ccaf77SBrad Bishop     auto refit = _refs.begin();
21379ccaf77SBrad Bishop     std::string absPath;
21479ccaf77SBrad Bishop     bool newObj;
21579ccaf77SBrad Bishop 
21679ccaf77SBrad Bishop     while (objit != objs.cend())
21779ccaf77SBrad Bishop     {
21879ccaf77SBrad Bishop         // Find the insertion point or the object to update.
219*615b2a8fSBrad Bishop         refit = std::lower_bound(refit, _refs.end(), objit->first,
22079ccaf77SBrad Bishop                                  compareFirst(RelPathCompare(_root)));
22179ccaf77SBrad Bishop 
22279ccaf77SBrad Bishop         absPath.assign(_root);
22379ccaf77SBrad Bishop         absPath.append(objit->first);
22479ccaf77SBrad Bishop 
22579ccaf77SBrad Bishop         newObj = false;
22679ccaf77SBrad Bishop         if (refit == _refs.end() || refit->first != absPath)
22779ccaf77SBrad Bishop         {
22879ccaf77SBrad Bishop             refit = _refs.insert(
229*615b2a8fSBrad Bishop                 refit, std::make_pair(absPath, decltype(_refs)::mapped_type()));
23079ccaf77SBrad Bishop             newObj = true;
23179ccaf77SBrad Bishop         }
23279ccaf77SBrad Bishop 
233b28990f3SDeepak Kodihalli         updateInterfaces(absPath, objit->second, refit, newObj,
234b28990f3SDeepak Kodihalli                          restoreFromCache);
23579ccaf77SBrad Bishop         ++objit;
23679ccaf77SBrad Bishop     }
23779ccaf77SBrad Bishop }
23879ccaf77SBrad Bishop 
23903f4cd95SBrad Bishop void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
24049aefb31SBrad Bishop {
241cda036f7SBrad Bishop     updateObjects(objs);
24249aefb31SBrad Bishop }
24349aefb31SBrad Bishop 
244*615b2a8fSBrad Bishop void Manager::handleEvent(sdbusplus::message::message& msg, const Event& event,
24568c80839SBrad Bishop                           const EventInfo& info)
24649aefb31SBrad Bishop {
24768c80839SBrad Bishop     auto& actions = std::get<1>(info);
2483d57f507SBrad Bishop 
24948547a85SBrad Bishop     for (auto& f : event)
2507b33777bSBrad Bishop     {
25107934a64SBrad Bishop         if (!f(_bus, msg, *this))
252064c94a6SBrad Bishop         {
253064c94a6SBrad Bishop             return;
254064c94a6SBrad Bishop         }
255064c94a6SBrad Bishop     }
2569007432aSBrad Bishop     for (auto& action : actions)
2577b33777bSBrad Bishop     {
25807934a64SBrad Bishop         action(_bus, *this);
2593d57f507SBrad Bishop     }
26049aefb31SBrad Bishop }
26149aefb31SBrad Bishop 
262*615b2a8fSBrad Bishop void Manager::destroyObjects(const std::vector<const char*>& paths)
2637b7e712cSBrad Bishop {
264a5cc34c2SBrad Bishop     std::string p;
265a5cc34c2SBrad Bishop 
2667b7e712cSBrad Bishop     for (const auto& path : paths)
267656a7d00SBrad Bishop     {
268a5cc34c2SBrad Bishop         p.assign(_root);
269a5cc34c2SBrad Bishop         p.append(path);
270a5cc34c2SBrad Bishop         _bus.emit_object_removed(p.c_str());
271a5cc34c2SBrad Bishop         _refs.erase(p);
272656a7d00SBrad Bishop     }
2737b7e712cSBrad Bishop }
274656a7d00SBrad Bishop 
275eb68a687SBrad Bishop void Manager::createObjects(
276eb68a687SBrad Bishop     const std::map<sdbusplus::message::object_path, Object>& objs)
277eb68a687SBrad Bishop {
278cda036f7SBrad Bishop     updateObjects(objs);
279eb68a687SBrad Bishop }
280eb68a687SBrad Bishop 
281*615b2a8fSBrad Bishop any_ns::any& Manager::getInterfaceHolder(const char* path,
282*615b2a8fSBrad Bishop                                          const char* interface)
283b83a21eaSBrad Bishop {
284150147aeSBrad Bishop     return const_cast<any_ns::any&>(
285*615b2a8fSBrad Bishop         const_cast<const Manager*>(this)->getInterfaceHolder(path, interface));
286b83a21eaSBrad Bishop }
287b83a21eaSBrad Bishop 
288*615b2a8fSBrad Bishop const any_ns::any& Manager::getInterfaceHolder(const char* path,
289*615b2a8fSBrad Bishop                                                const char* interface) const
290b83a21eaSBrad Bishop {
291b83a21eaSBrad Bishop     std::string p{path};
292b83a21eaSBrad Bishop     auto oit = _refs.find(_root + p);
293b83a21eaSBrad Bishop     if (oit == _refs.end())
294*615b2a8fSBrad Bishop         throw std::runtime_error(_root + p + " was not found");
295b83a21eaSBrad Bishop 
296b83a21eaSBrad Bishop     auto& obj = oit->second;
297b83a21eaSBrad Bishop     auto iit = obj.find(interface);
298b83a21eaSBrad Bishop     if (iit == obj.end())
299*615b2a8fSBrad Bishop         throw std::runtime_error("interface was not found");
300b83a21eaSBrad Bishop 
301150147aeSBrad Bishop     return iit->second;
302b83a21eaSBrad Bishop }
303b83a21eaSBrad Bishop 
304b28990f3SDeepak Kodihalli void Manager::restore()
305b28990f3SDeepak Kodihalli {
306b28990f3SDeepak Kodihalli     namespace fs = std::experimental::filesystem;
307b28990f3SDeepak Kodihalli 
308b28990f3SDeepak Kodihalli     if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
309b28990f3SDeepak Kodihalli     {
310b28990f3SDeepak Kodihalli         return;
311b28990f3SDeepak Kodihalli     }
312b28990f3SDeepak Kodihalli 
313b28990f3SDeepak Kodihalli     static const std::string remove =
314b28990f3SDeepak Kodihalli         std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
315b28990f3SDeepak Kodihalli 
316b28990f3SDeepak Kodihalli     std::map<sdbusplus::message::object_path, Object> objects;
317b28990f3SDeepak Kodihalli     for (const auto& dirent :
318b28990f3SDeepak Kodihalli          fs::recursive_directory_iterator(PIM_PERSIST_PATH))
319b28990f3SDeepak Kodihalli     {
320b28990f3SDeepak Kodihalli         const auto& path = dirent.path();
321b28990f3SDeepak Kodihalli         if (fs::is_regular_file(path))
322b28990f3SDeepak Kodihalli         {
323b28990f3SDeepak Kodihalli             auto ifaceName = path.filename().string();
324b28990f3SDeepak Kodihalli             auto objPath = path.parent_path().string();
325b28990f3SDeepak Kodihalli             objPath.erase(0, remove.length());
326b28990f3SDeepak Kodihalli             auto objit = objects.find(objPath);
327b28990f3SDeepak Kodihalli             Interface propertyMap{};
328b28990f3SDeepak Kodihalli             if (objects.end() != objit)
329b28990f3SDeepak Kodihalli             {
330b28990f3SDeepak Kodihalli                 auto& object = objit->second;
331b28990f3SDeepak Kodihalli                 object.emplace(std::move(ifaceName), std::move(propertyMap));
332b28990f3SDeepak Kodihalli             }
333b28990f3SDeepak Kodihalli             else
334b28990f3SDeepak Kodihalli             {
335b28990f3SDeepak Kodihalli                 Object object;
336b28990f3SDeepak Kodihalli                 object.emplace(std::move(ifaceName), std::move(propertyMap));
337b28990f3SDeepak Kodihalli                 objects.emplace(std::move(objPath), std::move(object));
338b28990f3SDeepak Kodihalli             }
339b28990f3SDeepak Kodihalli         }
340b28990f3SDeepak Kodihalli     }
341b28990f3SDeepak Kodihalli     if (!objects.empty())
342b28990f3SDeepak Kodihalli     {
343b28990f3SDeepak Kodihalli         auto restoreFromCache = true;
344b28990f3SDeepak Kodihalli         updateObjects(objects, restoreFromCache);
345b28990f3SDeepak Kodihalli     }
346b28990f3SDeepak Kodihalli }
347b28990f3SDeepak Kodihalli 
34849aefb31SBrad Bishop } // namespace manager
34949aefb31SBrad Bishop } // namespace inventory
35049aefb31SBrad Bishop } // namespace phosphor
35149aefb31SBrad Bishop 
35249aefb31SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
353