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 "manager.hpp" 17*a680d1efSPatrick Venture 1879ccaf77SBrad Bishop #include "errors.hpp" 1949aefb31SBrad Bishop 20*a680d1efSPatrick Venture #include <algorithm> 21*a680d1efSPatrick Venture #include <chrono> 22*a680d1efSPatrick Venture #include <exception> 23*a680d1efSPatrick Venture #include <experimental/filesystem> 24*a680d1efSPatrick Venture #include <iostream> 25*a680d1efSPatrick Venture #include <phosphor-logging/log.hpp> 26*a680d1efSPatrick Venture 2724424983SBrad Bishop using namespace std::literals::chrono_literals; 2824424983SBrad Bishop 2949aefb31SBrad Bishop namespace phosphor 3049aefb31SBrad Bishop { 3149aefb31SBrad Bishop namespace inventory 3249aefb31SBrad Bishop { 3349aefb31SBrad Bishop namespace manager 3449aefb31SBrad Bishop { 3549aefb31SBrad Bishop /** @brief Fowrarding signal callback. 3649aefb31SBrad Bishop * 3749aefb31SBrad Bishop * Extracts per-signal specific context and forwards the call to the manager 3849aefb31SBrad Bishop * instance. 3949aefb31SBrad Bishop */ 4049aefb31SBrad Bishop auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept 4149aefb31SBrad Bishop { 427b33777bSBrad Bishop try 437b33777bSBrad Bishop { 4449aefb31SBrad Bishop auto msg = sdbusplus::message::message(m); 4549aefb31SBrad Bishop auto& args = *static_cast<Manager::SigArg*>(data); 4649aefb31SBrad Bishop sd_bus_message_ref(m); 4749aefb31SBrad Bishop auto& mgr = *std::get<0>(args); 48615b2a8fSBrad Bishop mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)), 4968c80839SBrad Bishop *std::get<2>(args)); 5049aefb31SBrad Bishop } 517b33777bSBrad Bishop catch (const std::exception& e) 527b33777bSBrad Bishop { 5349aefb31SBrad Bishop std::cerr << e.what() << std::endl; 5449aefb31SBrad Bishop } 5549aefb31SBrad Bishop 5649aefb31SBrad Bishop return 0; 5749aefb31SBrad Bishop } 5849aefb31SBrad Bishop 59615b2a8fSBrad Bishop Manager::Manager(sdbusplus::bus::bus&& bus, const char* busname, 60615b2a8fSBrad Bishop const char* root, const char* iface) : 6112f8a3c8SBrad Bishop ServerObject<ManagerIface>(bus, root), 62615b2a8fSBrad Bishop _shutdown(false), _root(root), _bus(std::move(bus)), _manager(_bus, root) 6349aefb31SBrad Bishop { 6468c80839SBrad Bishop for (auto& group : _events) 6568c80839SBrad Bishop { 66615b2a8fSBrad Bishop for (auto pEvent : std::get<std::vector<EventBasePtr>>(group)) 6768c80839SBrad Bishop { 68615b2a8fSBrad Bishop if (pEvent->type != Event::Type::DBUS_SIGNAL) 697b33777bSBrad Bishop { 704f20a3e3SBrad Bishop continue; 717b33777bSBrad Bishop } 724f20a3e3SBrad Bishop 7368c80839SBrad Bishop // Create a callback context for this event group. 74615b2a8fSBrad Bishop auto dbusEvent = static_cast<DbusSignal*>(pEvent.get()); 7568c80839SBrad Bishop 7668c80839SBrad Bishop // Go ahead and store an iterator pointing at 7768c80839SBrad Bishop // the event data to avoid lookups later since 7868c80839SBrad Bishop // additional signal callbacks aren't added 7968c80839SBrad Bishop // after the manager is constructed. 8049aefb31SBrad Bishop _sigargs.emplace_back( 81615b2a8fSBrad Bishop std::make_unique<SigArg>(this, dbusEvent, &group)); 8268c80839SBrad Bishop 8349aefb31SBrad Bishop // Register our callback and the context for 8468c80839SBrad Bishop // each signal event. 85615b2a8fSBrad Bishop _matches.emplace_back(_bus, dbusEvent->signature, _signal, 861ab880a1SBrad Bishop _sigargs.back().get()); 8749aefb31SBrad Bishop } 8868c80839SBrad Bishop } 8949aefb31SBrad Bishop 9049aefb31SBrad Bishop _bus.request_name(busname); 91b28990f3SDeepak Kodihalli 92b28990f3SDeepak Kodihalli // Restore any persistent inventory 93b28990f3SDeepak Kodihalli restore(); 9449aefb31SBrad Bishop } 9549aefb31SBrad Bishop 9649aefb31SBrad Bishop void Manager::shutdown() noexcept 9749aefb31SBrad Bishop { 9849aefb31SBrad Bishop _shutdown = true; 9949aefb31SBrad Bishop } 10049aefb31SBrad Bishop 10149aefb31SBrad Bishop void Manager::run() noexcept 10249aefb31SBrad Bishop { 1033e4a19a3SBrad Bishop sdbusplus::message::message unusedMsg{nullptr}; 1043e4a19a3SBrad Bishop 1053e4a19a3SBrad Bishop // Run startup events. 1063e4a19a3SBrad Bishop for (auto& group : _events) 1073e4a19a3SBrad Bishop { 108615b2a8fSBrad Bishop for (auto pEvent : std::get<std::vector<EventBasePtr>>(group)) 1093e4a19a3SBrad Bishop { 110615b2a8fSBrad Bishop if (pEvent->type == Event::Type::STARTUP) 1113e4a19a3SBrad Bishop { 1123e4a19a3SBrad Bishop handleEvent(unusedMsg, *pEvent, group); 1133e4a19a3SBrad Bishop } 1143e4a19a3SBrad Bishop } 1153e4a19a3SBrad Bishop } 1163e4a19a3SBrad Bishop 1177b33777bSBrad Bishop while (!_shutdown) 1187b33777bSBrad Bishop { 1197b33777bSBrad Bishop try 1207b33777bSBrad Bishop { 12149aefb31SBrad Bishop _bus.process_discard(); 12224424983SBrad Bishop _bus.wait((5000000us).count()); 12349aefb31SBrad Bishop } 1247b33777bSBrad Bishop catch (const std::exception& e) 1257b33777bSBrad Bishop { 12649aefb31SBrad Bishop std::cerr << e.what() << std::endl; 12749aefb31SBrad Bishop } 12849aefb31SBrad Bishop } 12949aefb31SBrad Bishop } 13049aefb31SBrad Bishop 131615b2a8fSBrad Bishop void Manager::updateInterfaces(const sdbusplus::message::object_path& path, 13279ccaf77SBrad Bishop const Object& interfaces, 133615b2a8fSBrad Bishop ObjectReferences::iterator pos, bool newObject, 134b28990f3SDeepak Kodihalli bool restoreFromCache) 13579ccaf77SBrad Bishop { 13679ccaf77SBrad Bishop auto& refaces = pos->second; 13779ccaf77SBrad Bishop auto ifaceit = interfaces.cbegin(); 13879ccaf77SBrad Bishop auto opsit = _makers.cbegin(); 13979ccaf77SBrad Bishop auto refaceit = refaces.begin(); 14079ccaf77SBrad Bishop std::vector<std::string> signals; 14179ccaf77SBrad Bishop 14279ccaf77SBrad Bishop while (ifaceit != interfaces.cend()) 14379ccaf77SBrad Bishop { 14479ccaf77SBrad Bishop try 14579ccaf77SBrad Bishop { 14679ccaf77SBrad Bishop // Find the binding ops for this interface. 147615b2a8fSBrad Bishop opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first, 14879ccaf77SBrad Bishop compareFirst(_makers.key_comp())); 14979ccaf77SBrad Bishop 15079ccaf77SBrad Bishop if (opsit == _makers.cend() || opsit->first != ifaceit->first) 15179ccaf77SBrad Bishop { 15279ccaf77SBrad Bishop // This interface is not supported. 153615b2a8fSBrad Bishop throw InterfaceError("Encountered unsupported interface.", 15479ccaf77SBrad Bishop ifaceit->first); 15579ccaf77SBrad Bishop } 15679ccaf77SBrad Bishop 15779ccaf77SBrad Bishop // Find the binding insertion point or the binding to update. 158615b2a8fSBrad Bishop refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first, 15979ccaf77SBrad Bishop compareFirst(refaces.key_comp())); 16079ccaf77SBrad Bishop 16179ccaf77SBrad Bishop if (refaceit == refaces.end() || refaceit->first != ifaceit->first) 16279ccaf77SBrad Bishop { 16379ccaf77SBrad Bishop // Add the new interface. 16479ccaf77SBrad Bishop auto& ctor = std::get<MakerType>(opsit->second); 16579ccaf77SBrad Bishop refaceit = refaces.insert( 16679ccaf77SBrad Bishop refaceit, 167615b2a8fSBrad Bishop std::make_pair(ifaceit->first, ctor(_bus, path.str.c_str(), 16879ccaf77SBrad Bishop ifaceit->second))); 16979ccaf77SBrad Bishop signals.push_back(ifaceit->first); 17079ccaf77SBrad Bishop } 17179ccaf77SBrad Bishop else 17279ccaf77SBrad Bishop { 17379ccaf77SBrad Bishop // Set the new property values. 17479ccaf77SBrad Bishop auto& assign = std::get<AssignerType>(opsit->second); 17579ccaf77SBrad Bishop assign(ifaceit->second, refaceit->second); 17679ccaf77SBrad Bishop } 177b28990f3SDeepak Kodihalli if (!restoreFromCache) 178b28990f3SDeepak Kodihalli { 1796620e98dSDeepak Kodihalli auto& serialize = std::get<SerializerType>(opsit->second); 1806620e98dSDeepak Kodihalli serialize(path, ifaceit->first, refaceit->second); 18179ccaf77SBrad Bishop } 182b28990f3SDeepak Kodihalli else 183b28990f3SDeepak Kodihalli { 184b28990f3SDeepak Kodihalli auto& deserialize = std::get<DeserializerType>(opsit->second); 185b28990f3SDeepak Kodihalli deserialize(path, ifaceit->first, refaceit->second); 186b28990f3SDeepak Kodihalli } 187b28990f3SDeepak Kodihalli } 18879ccaf77SBrad Bishop catch (const InterfaceError& e) 18979ccaf77SBrad Bishop { 19079ccaf77SBrad Bishop // Reset the binding ops iterator since we are 19179ccaf77SBrad Bishop // at the end. 19279ccaf77SBrad Bishop opsit = _makers.cbegin(); 19379ccaf77SBrad Bishop e.log(); 19479ccaf77SBrad Bishop } 19579ccaf77SBrad Bishop 19679ccaf77SBrad Bishop ++ifaceit; 19779ccaf77SBrad Bishop } 19879ccaf77SBrad Bishop 19979ccaf77SBrad Bishop if (newObject) 20079ccaf77SBrad Bishop { 20179ccaf77SBrad Bishop _bus.emit_object_added(path.str.c_str()); 20279ccaf77SBrad Bishop } 20379ccaf77SBrad Bishop else if (!signals.empty()) 20479ccaf77SBrad Bishop { 205a8ff8154SGunnar Mills _bus.emit_interfaces_added(path.str.c_str(), signals); 20679ccaf77SBrad Bishop } 20779ccaf77SBrad Bishop } 20879ccaf77SBrad Bishop 20979ccaf77SBrad Bishop void Manager::updateObjects( 210b28990f3SDeepak Kodihalli const std::map<sdbusplus::message::object_path, Object>& objs, 211b28990f3SDeepak Kodihalli bool restoreFromCache) 21279ccaf77SBrad Bishop { 21379ccaf77SBrad Bishop auto objit = objs.cbegin(); 21479ccaf77SBrad Bishop auto refit = _refs.begin(); 21579ccaf77SBrad Bishop std::string absPath; 21679ccaf77SBrad Bishop bool newObj; 21779ccaf77SBrad Bishop 21879ccaf77SBrad Bishop while (objit != objs.cend()) 21979ccaf77SBrad Bishop { 22079ccaf77SBrad Bishop // Find the insertion point or the object to update. 221615b2a8fSBrad Bishop refit = std::lower_bound(refit, _refs.end(), objit->first, 22279ccaf77SBrad Bishop compareFirst(RelPathCompare(_root))); 22379ccaf77SBrad Bishop 22479ccaf77SBrad Bishop absPath.assign(_root); 22579ccaf77SBrad Bishop absPath.append(objit->first); 22679ccaf77SBrad Bishop 22779ccaf77SBrad Bishop newObj = false; 22879ccaf77SBrad Bishop if (refit == _refs.end() || refit->first != absPath) 22979ccaf77SBrad Bishop { 23079ccaf77SBrad Bishop refit = _refs.insert( 231615b2a8fSBrad Bishop refit, std::make_pair(absPath, decltype(_refs)::mapped_type())); 23279ccaf77SBrad Bishop newObj = true; 23379ccaf77SBrad Bishop } 23479ccaf77SBrad Bishop 235b28990f3SDeepak Kodihalli updateInterfaces(absPath, objit->second, refit, newObj, 236b28990f3SDeepak Kodihalli restoreFromCache); 23779ccaf77SBrad Bishop ++objit; 23879ccaf77SBrad Bishop } 23979ccaf77SBrad Bishop } 24079ccaf77SBrad Bishop 24103f4cd95SBrad Bishop void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs) 24249aefb31SBrad Bishop { 243cda036f7SBrad Bishop updateObjects(objs); 24449aefb31SBrad Bishop } 24549aefb31SBrad Bishop 246615b2a8fSBrad Bishop void Manager::handleEvent(sdbusplus::message::message& msg, const Event& event, 24768c80839SBrad Bishop const EventInfo& info) 24849aefb31SBrad Bishop { 24968c80839SBrad Bishop auto& actions = std::get<1>(info); 2503d57f507SBrad Bishop 25148547a85SBrad Bishop for (auto& f : event) 2527b33777bSBrad Bishop { 25307934a64SBrad Bishop if (!f(_bus, msg, *this)) 254064c94a6SBrad Bishop { 255064c94a6SBrad Bishop return; 256064c94a6SBrad Bishop } 257064c94a6SBrad Bishop } 2589007432aSBrad Bishop for (auto& action : actions) 2597b33777bSBrad Bishop { 26007934a64SBrad Bishop action(_bus, *this); 2613d57f507SBrad Bishop } 26249aefb31SBrad Bishop } 26349aefb31SBrad Bishop 264615b2a8fSBrad Bishop void Manager::destroyObjects(const std::vector<const char*>& paths) 2657b7e712cSBrad Bishop { 266a5cc34c2SBrad Bishop std::string p; 267a5cc34c2SBrad Bishop 2687b7e712cSBrad Bishop for (const auto& path : paths) 269656a7d00SBrad Bishop { 270a5cc34c2SBrad Bishop p.assign(_root); 271a5cc34c2SBrad Bishop p.append(path); 272a5cc34c2SBrad Bishop _bus.emit_object_removed(p.c_str()); 273a5cc34c2SBrad Bishop _refs.erase(p); 274656a7d00SBrad Bishop } 2757b7e712cSBrad Bishop } 276656a7d00SBrad Bishop 277eb68a687SBrad Bishop void Manager::createObjects( 278eb68a687SBrad Bishop const std::map<sdbusplus::message::object_path, Object>& objs) 279eb68a687SBrad Bishop { 280cda036f7SBrad Bishop updateObjects(objs); 281eb68a687SBrad Bishop } 282eb68a687SBrad Bishop 283615b2a8fSBrad Bishop any_ns::any& Manager::getInterfaceHolder(const char* path, 284615b2a8fSBrad Bishop const char* interface) 285b83a21eaSBrad Bishop { 286150147aeSBrad Bishop return const_cast<any_ns::any&>( 287615b2a8fSBrad Bishop const_cast<const Manager*>(this)->getInterfaceHolder(path, interface)); 288b83a21eaSBrad Bishop } 289b83a21eaSBrad Bishop 290615b2a8fSBrad Bishop const any_ns::any& Manager::getInterfaceHolder(const char* path, 291615b2a8fSBrad Bishop const char* interface) const 292b83a21eaSBrad Bishop { 293b83a21eaSBrad Bishop std::string p{path}; 294b83a21eaSBrad Bishop auto oit = _refs.find(_root + p); 295b83a21eaSBrad Bishop if (oit == _refs.end()) 296615b2a8fSBrad Bishop throw std::runtime_error(_root + p + " was not found"); 297b83a21eaSBrad Bishop 298b83a21eaSBrad Bishop auto& obj = oit->second; 299b83a21eaSBrad Bishop auto iit = obj.find(interface); 300b83a21eaSBrad Bishop if (iit == obj.end()) 301615b2a8fSBrad Bishop throw std::runtime_error("interface was not found"); 302b83a21eaSBrad Bishop 303150147aeSBrad Bishop return iit->second; 304b83a21eaSBrad Bishop } 305b83a21eaSBrad Bishop 306b28990f3SDeepak Kodihalli void Manager::restore() 307b28990f3SDeepak Kodihalli { 308b28990f3SDeepak Kodihalli namespace fs = std::experimental::filesystem; 309b28990f3SDeepak Kodihalli 310b28990f3SDeepak Kodihalli if (!fs::exists(fs::path(PIM_PERSIST_PATH))) 311b28990f3SDeepak Kodihalli { 312b28990f3SDeepak Kodihalli return; 313b28990f3SDeepak Kodihalli } 314b28990f3SDeepak Kodihalli 315b28990f3SDeepak Kodihalli static const std::string remove = 316b28990f3SDeepak Kodihalli std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT; 317b28990f3SDeepak Kodihalli 318b28990f3SDeepak Kodihalli std::map<sdbusplus::message::object_path, Object> objects; 319b28990f3SDeepak Kodihalli for (const auto& dirent : 320b28990f3SDeepak Kodihalli fs::recursive_directory_iterator(PIM_PERSIST_PATH)) 321b28990f3SDeepak Kodihalli { 322b28990f3SDeepak Kodihalli const auto& path = dirent.path(); 323b28990f3SDeepak Kodihalli if (fs::is_regular_file(path)) 324b28990f3SDeepak Kodihalli { 325b28990f3SDeepak Kodihalli auto ifaceName = path.filename().string(); 326b28990f3SDeepak Kodihalli auto objPath = path.parent_path().string(); 327b28990f3SDeepak Kodihalli objPath.erase(0, remove.length()); 328b28990f3SDeepak Kodihalli auto objit = objects.find(objPath); 329b28990f3SDeepak Kodihalli Interface propertyMap{}; 330b28990f3SDeepak Kodihalli if (objects.end() != objit) 331b28990f3SDeepak Kodihalli { 332b28990f3SDeepak Kodihalli auto& object = objit->second; 333b28990f3SDeepak Kodihalli object.emplace(std::move(ifaceName), std::move(propertyMap)); 334b28990f3SDeepak Kodihalli } 335b28990f3SDeepak Kodihalli else 336b28990f3SDeepak Kodihalli { 337b28990f3SDeepak Kodihalli Object object; 338b28990f3SDeepak Kodihalli object.emplace(std::move(ifaceName), std::move(propertyMap)); 339b28990f3SDeepak Kodihalli objects.emplace(std::move(objPath), std::move(object)); 340b28990f3SDeepak Kodihalli } 341b28990f3SDeepak Kodihalli } 342b28990f3SDeepak Kodihalli } 343b28990f3SDeepak Kodihalli if (!objects.empty()) 344b28990f3SDeepak Kodihalli { 345b28990f3SDeepak Kodihalli auto restoreFromCache = true; 346b28990f3SDeepak Kodihalli updateObjects(objects, restoreFromCache); 347b28990f3SDeepak Kodihalli } 348b28990f3SDeepak Kodihalli } 349b28990f3SDeepak Kodihalli 35049aefb31SBrad Bishop } // namespace manager 35149aefb31SBrad Bishop } // namespace inventory 35249aefb31SBrad Bishop } // namespace phosphor 35349aefb31SBrad Bishop 35449aefb31SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 355