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