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" 17a680d1efSPatrick Venture 1879ccaf77SBrad Bishop #include "errors.hpp" 1949aefb31SBrad Bishop 20a83db30eSBrad Bishop #include <phosphor-logging/log.hpp> 21a83db30eSBrad Bishop 22a680d1efSPatrick Venture #include <algorithm> 23a680d1efSPatrick Venture #include <chrono> 24a680d1efSPatrick Venture #include <exception> 25e6b21c74SKun Yi #include <filesystem> 26a680d1efSPatrick Venture #include <iostream> 27a680d1efSPatrick Venture 2824424983SBrad Bishop using namespace std::literals::chrono_literals; 2924424983SBrad Bishop 3049aefb31SBrad Bishop namespace phosphor 3149aefb31SBrad Bishop { 3249aefb31SBrad Bishop namespace inventory 3349aefb31SBrad Bishop { 3449aefb31SBrad Bishop namespace manager 3549aefb31SBrad Bishop { 3649aefb31SBrad Bishop /** @brief Fowrarding signal callback. 3749aefb31SBrad Bishop * 3849aefb31SBrad Bishop * Extracts per-signal specific context and forwards the call to the manager 3949aefb31SBrad Bishop * instance. 4049aefb31SBrad Bishop */ 4149aefb31SBrad Bishop auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept 4249aefb31SBrad Bishop { 437b33777bSBrad Bishop try 447b33777bSBrad Bishop { 4549aefb31SBrad Bishop auto msg = sdbusplus::message::message(m); 4649aefb31SBrad Bishop auto& args = *static_cast<Manager::SigArg*>(data); 4749aefb31SBrad Bishop sd_bus_message_ref(m); 4849aefb31SBrad Bishop auto& mgr = *std::get<0>(args); 49615b2a8fSBrad Bishop mgr.handleEvent(msg, static_cast<const DbusSignal&>(*std::get<1>(args)), 5068c80839SBrad Bishop *std::get<2>(args)); 5149aefb31SBrad Bishop } 527b33777bSBrad Bishop catch (const std::exception& e) 537b33777bSBrad Bishop { 5449aefb31SBrad Bishop std::cerr << e.what() << std::endl; 5549aefb31SBrad Bishop } 5649aefb31SBrad Bishop 5749aefb31SBrad Bishop return 0; 5849aefb31SBrad Bishop } 5949aefb31SBrad Bishop 6020c9435cSBrad Bishop Manager::Manager(sdbusplus::bus::bus&& bus, const char* root) : 614627a9ccSBrad Bishop ServerObject<ManagerIface>(bus, root), _root(root), _bus(std::move(bus)), 624627a9ccSBrad Bishop _manager(_bus, root), 63852db67bSMatt Spinler #ifdef CREATE_ASSOCIATIONS 644627a9ccSBrad Bishop _associations(_bus), 65852db67bSMatt Spinler #endif 664627a9ccSBrad Bishop _status(ManagerStatus::STARTING) 6749aefb31SBrad Bishop { 6868c80839SBrad Bishop for (auto& group : _events) 6968c80839SBrad Bishop { 70615b2a8fSBrad Bishop for (auto pEvent : std::get<std::vector<EventBasePtr>>(group)) 7168c80839SBrad Bishop { 72615b2a8fSBrad Bishop if (pEvent->type != Event::Type::DBUS_SIGNAL) 737b33777bSBrad Bishop { 744f20a3e3SBrad Bishop continue; 757b33777bSBrad Bishop } 764f20a3e3SBrad Bishop 7768c80839SBrad Bishop // Create a callback context for this event group. 78615b2a8fSBrad Bishop auto dbusEvent = static_cast<DbusSignal*>(pEvent.get()); 7968c80839SBrad Bishop 8068c80839SBrad Bishop // Go ahead and store an iterator pointing at 8168c80839SBrad Bishop // the event data to avoid lookups later since 8268c80839SBrad Bishop // additional signal callbacks aren't added 8368c80839SBrad Bishop // after the manager is constructed. 8449aefb31SBrad Bishop _sigargs.emplace_back( 85615b2a8fSBrad Bishop std::make_unique<SigArg>(this, dbusEvent, &group)); 8668c80839SBrad Bishop 8749aefb31SBrad Bishop // Register our callback and the context for 8868c80839SBrad Bishop // each signal event. 89615b2a8fSBrad Bishop _matches.emplace_back(_bus, dbusEvent->signature, _signal, 901ab880a1SBrad Bishop _sigargs.back().get()); 9149aefb31SBrad Bishop } 9268c80839SBrad Bishop } 9349aefb31SBrad Bishop 94b28990f3SDeepak Kodihalli // Restore any persistent inventory 95b28990f3SDeepak Kodihalli restore(); 9649aefb31SBrad Bishop } 9749aefb31SBrad Bishop 9849aefb31SBrad Bishop void Manager::shutdown() noexcept 9949aefb31SBrad Bishop { 1004627a9ccSBrad Bishop _status = ManagerStatus::STOPPING; 10149aefb31SBrad Bishop } 10249aefb31SBrad Bishop 10320c9435cSBrad Bishop void Manager::run(const char* busname) 10449aefb31SBrad Bishop { 1053e4a19a3SBrad Bishop sdbusplus::message::message unusedMsg{nullptr}; 1063e4a19a3SBrad Bishop 1073e4a19a3SBrad Bishop // Run startup events. 1083e4a19a3SBrad Bishop for (auto& group : _events) 1093e4a19a3SBrad Bishop { 110615b2a8fSBrad Bishop for (auto pEvent : std::get<std::vector<EventBasePtr>>(group)) 1113e4a19a3SBrad Bishop { 112615b2a8fSBrad Bishop if (pEvent->type == Event::Type::STARTUP) 1133e4a19a3SBrad Bishop { 1143e4a19a3SBrad Bishop handleEvent(unusedMsg, *pEvent, group); 1153e4a19a3SBrad Bishop } 1163e4a19a3SBrad Bishop } 1173e4a19a3SBrad Bishop } 1183e4a19a3SBrad Bishop 1194627a9ccSBrad Bishop _status = ManagerStatus::RUNNING; 12020c9435cSBrad Bishop _bus.request_name(busname); 1214627a9ccSBrad Bishop 1224627a9ccSBrad Bishop while (_status != ManagerStatus::STOPPING) 1237b33777bSBrad Bishop { 1247b33777bSBrad Bishop try 1257b33777bSBrad Bishop { 12649aefb31SBrad Bishop _bus.process_discard(); 12724424983SBrad Bishop _bus.wait((5000000us).count()); 12849aefb31SBrad Bishop } 1297b33777bSBrad Bishop catch (const std::exception& e) 1307b33777bSBrad Bishop { 13149aefb31SBrad Bishop std::cerr << e.what() << std::endl; 13249aefb31SBrad Bishop } 13349aefb31SBrad Bishop } 13449aefb31SBrad Bishop } 13549aefb31SBrad Bishop 136615b2a8fSBrad Bishop void Manager::updateInterfaces(const sdbusplus::message::object_path& path, 13779ccaf77SBrad Bishop const Object& interfaces, 138615b2a8fSBrad Bishop ObjectReferences::iterator pos, bool newObject, 139b28990f3SDeepak Kodihalli bool restoreFromCache) 14079ccaf77SBrad Bishop { 14179ccaf77SBrad Bishop auto& refaces = pos->second; 14279ccaf77SBrad Bishop auto ifaceit = interfaces.cbegin(); 14379ccaf77SBrad Bishop auto opsit = _makers.cbegin(); 14479ccaf77SBrad Bishop auto refaceit = refaces.begin(); 14579ccaf77SBrad Bishop std::vector<std::string> signals; 14679ccaf77SBrad Bishop 14779ccaf77SBrad Bishop while (ifaceit != interfaces.cend()) 14879ccaf77SBrad Bishop { 14979ccaf77SBrad Bishop try 15079ccaf77SBrad Bishop { 15179ccaf77SBrad Bishop // Find the binding ops for this interface. 152615b2a8fSBrad Bishop opsit = std::lower_bound(opsit, _makers.cend(), ifaceit->first, 15379ccaf77SBrad Bishop compareFirst(_makers.key_comp())); 15479ccaf77SBrad Bishop 15579ccaf77SBrad Bishop if (opsit == _makers.cend() || opsit->first != ifaceit->first) 15679ccaf77SBrad Bishop { 15779ccaf77SBrad Bishop // This interface is not supported. 158615b2a8fSBrad Bishop throw InterfaceError("Encountered unsupported interface.", 15979ccaf77SBrad Bishop ifaceit->first); 16079ccaf77SBrad Bishop } 16179ccaf77SBrad Bishop 16279ccaf77SBrad Bishop // Find the binding insertion point or the binding to update. 163615b2a8fSBrad Bishop refaceit = std::lower_bound(refaceit, refaces.end(), ifaceit->first, 16479ccaf77SBrad Bishop compareFirst(refaces.key_comp())); 16579ccaf77SBrad Bishop 16679ccaf77SBrad Bishop if (refaceit == refaces.end() || refaceit->first != ifaceit->first) 16779ccaf77SBrad Bishop { 16879ccaf77SBrad Bishop // Add the new interface. 16902763c68SBrad Bishop auto& ctor = std::get<MakeInterfaceType>(opsit->second); 170*23a8d935SBrad Bishop // skipSignal = true here to avoid getting PropertiesChanged 171*23a8d935SBrad Bishop // signals while the interface is constructed. We'll emit an 172*23a8d935SBrad Bishop // ObjectManager signal for this interface below. 17379ccaf77SBrad Bishop refaceit = refaces.insert( 174e96f2aa7SBrad Bishop refaceit, std::make_pair(ifaceit->first, 175e96f2aa7SBrad Bishop ctor(_bus, path.str.c_str(), 176*23a8d935SBrad Bishop ifaceit->second, true))); 17779ccaf77SBrad Bishop signals.push_back(ifaceit->first); 17879ccaf77SBrad Bishop } 17979ccaf77SBrad Bishop else 18079ccaf77SBrad Bishop { 18179ccaf77SBrad Bishop // Set the new property values. 18202763c68SBrad Bishop auto& assign = std::get<AssignInterfaceType>(opsit->second); 183*23a8d935SBrad Bishop assign(ifaceit->second, refaceit->second, 184*23a8d935SBrad Bishop _status != ManagerStatus::RUNNING); 18579ccaf77SBrad Bishop } 186b28990f3SDeepak Kodihalli if (!restoreFromCache) 187b28990f3SDeepak Kodihalli { 18802763c68SBrad Bishop auto& serialize = 18902763c68SBrad Bishop std::get<SerializeInterfaceType<SerialOps>>(opsit->second); 1906620e98dSDeepak Kodihalli serialize(path, ifaceit->first, refaceit->second); 19179ccaf77SBrad Bishop } 192b28990f3SDeepak Kodihalli else 193b28990f3SDeepak Kodihalli { 19402763c68SBrad Bishop auto& deserialize = 19502763c68SBrad Bishop std::get<DeserializeInterfaceType<SerialOps>>( 19602763c68SBrad Bishop opsit->second); 197b28990f3SDeepak Kodihalli deserialize(path, ifaceit->first, refaceit->second); 198b28990f3SDeepak Kodihalli } 199b28990f3SDeepak Kodihalli } 20079ccaf77SBrad Bishop catch (const InterfaceError& e) 20179ccaf77SBrad Bishop { 20279ccaf77SBrad Bishop // Reset the binding ops iterator since we are 20379ccaf77SBrad Bishop // at the end. 20479ccaf77SBrad Bishop opsit = _makers.cbegin(); 20579ccaf77SBrad Bishop e.log(); 20679ccaf77SBrad Bishop } 20779ccaf77SBrad Bishop 20879ccaf77SBrad Bishop ++ifaceit; 20979ccaf77SBrad Bishop } 21079ccaf77SBrad Bishop 211*23a8d935SBrad Bishop if (_status == ManagerStatus::RUNNING) 212*23a8d935SBrad Bishop { 21379ccaf77SBrad Bishop if (newObject) 21479ccaf77SBrad Bishop { 21579ccaf77SBrad Bishop _bus.emit_object_added(path.str.c_str()); 21679ccaf77SBrad Bishop } 21779ccaf77SBrad Bishop else if (!signals.empty()) 21879ccaf77SBrad Bishop { 219a8ff8154SGunnar Mills _bus.emit_interfaces_added(path.str.c_str(), signals); 22079ccaf77SBrad Bishop } 22179ccaf77SBrad Bishop } 222*23a8d935SBrad Bishop } 22379ccaf77SBrad Bishop 22479ccaf77SBrad Bishop void Manager::updateObjects( 225b28990f3SDeepak Kodihalli const std::map<sdbusplus::message::object_path, Object>& objs, 226b28990f3SDeepak Kodihalli bool restoreFromCache) 22779ccaf77SBrad Bishop { 22879ccaf77SBrad Bishop auto objit = objs.cbegin(); 22979ccaf77SBrad Bishop auto refit = _refs.begin(); 23079ccaf77SBrad Bishop std::string absPath; 23179ccaf77SBrad Bishop bool newObj; 23279ccaf77SBrad Bishop 23379ccaf77SBrad Bishop while (objit != objs.cend()) 23479ccaf77SBrad Bishop { 23579ccaf77SBrad Bishop // Find the insertion point or the object to update. 236615b2a8fSBrad Bishop refit = std::lower_bound(refit, _refs.end(), objit->first, 23779ccaf77SBrad Bishop compareFirst(RelPathCompare(_root))); 23879ccaf77SBrad Bishop 23979ccaf77SBrad Bishop absPath.assign(_root); 24079ccaf77SBrad Bishop absPath.append(objit->first); 24179ccaf77SBrad Bishop 24279ccaf77SBrad Bishop newObj = false; 24379ccaf77SBrad Bishop if (refit == _refs.end() || refit->first != absPath) 24479ccaf77SBrad Bishop { 24579ccaf77SBrad Bishop refit = _refs.insert( 246615b2a8fSBrad Bishop refit, std::make_pair(absPath, decltype(_refs)::mapped_type())); 24779ccaf77SBrad Bishop newObj = true; 24879ccaf77SBrad Bishop } 24979ccaf77SBrad Bishop 250b28990f3SDeepak Kodihalli updateInterfaces(absPath, objit->second, refit, newObj, 251b28990f3SDeepak Kodihalli restoreFromCache); 252852db67bSMatt Spinler #ifdef CREATE_ASSOCIATIONS 253852db67bSMatt Spinler if (newObj) 254852db67bSMatt Spinler { 255*23a8d935SBrad Bishop _associations.createAssociations(absPath, 256*23a8d935SBrad Bishop state != ManagerStatus::RUNNING); 257852db67bSMatt Spinler } 258852db67bSMatt Spinler #endif 25979ccaf77SBrad Bishop ++objit; 26079ccaf77SBrad Bishop } 26179ccaf77SBrad Bishop } 26279ccaf77SBrad Bishop 26303f4cd95SBrad Bishop void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs) 26449aefb31SBrad Bishop { 265cda036f7SBrad Bishop updateObjects(objs); 26649aefb31SBrad Bishop } 26749aefb31SBrad Bishop 268615b2a8fSBrad Bishop void Manager::handleEvent(sdbusplus::message::message& msg, const Event& event, 26968c80839SBrad Bishop const EventInfo& info) 27049aefb31SBrad Bishop { 27168c80839SBrad Bishop auto& actions = std::get<1>(info); 2723d57f507SBrad Bishop 27348547a85SBrad Bishop for (auto& f : event) 2747b33777bSBrad Bishop { 27507934a64SBrad Bishop if (!f(_bus, msg, *this)) 276064c94a6SBrad Bishop { 277064c94a6SBrad Bishop return; 278064c94a6SBrad Bishop } 279064c94a6SBrad Bishop } 2809007432aSBrad Bishop for (auto& action : actions) 2817b33777bSBrad Bishop { 28207934a64SBrad Bishop action(_bus, *this); 2833d57f507SBrad Bishop } 28449aefb31SBrad Bishop } 28549aefb31SBrad Bishop 286615b2a8fSBrad Bishop void Manager::destroyObjects(const std::vector<const char*>& paths) 2877b7e712cSBrad Bishop { 288a5cc34c2SBrad Bishop std::string p; 289a5cc34c2SBrad Bishop 2907b7e712cSBrad Bishop for (const auto& path : paths) 291656a7d00SBrad Bishop { 292a5cc34c2SBrad Bishop p.assign(_root); 293a5cc34c2SBrad Bishop p.append(path); 294a5cc34c2SBrad Bishop _bus.emit_object_removed(p.c_str()); 295a5cc34c2SBrad Bishop _refs.erase(p); 296656a7d00SBrad Bishop } 2977b7e712cSBrad Bishop } 298656a7d00SBrad Bishop 299eb68a687SBrad Bishop void Manager::createObjects( 300eb68a687SBrad Bishop const std::map<sdbusplus::message::object_path, Object>& objs) 301eb68a687SBrad Bishop { 302cda036f7SBrad Bishop updateObjects(objs); 303eb68a687SBrad Bishop } 304eb68a687SBrad Bishop 30525d54b51SBrad Bishop std::any& Manager::getInterfaceHolder(const char* path, const char* interface) 306b83a21eaSBrad Bishop { 30725d54b51SBrad Bishop return const_cast<std::any&>( 308615b2a8fSBrad Bishop const_cast<const Manager*>(this)->getInterfaceHolder(path, interface)); 309b83a21eaSBrad Bishop } 310b83a21eaSBrad Bishop 31125d54b51SBrad Bishop const std::any& Manager::getInterfaceHolder(const char* path, 312615b2a8fSBrad Bishop const char* interface) const 313b83a21eaSBrad Bishop { 314b83a21eaSBrad Bishop std::string p{path}; 315b83a21eaSBrad Bishop auto oit = _refs.find(_root + p); 316b83a21eaSBrad Bishop if (oit == _refs.end()) 317615b2a8fSBrad Bishop throw std::runtime_error(_root + p + " was not found"); 318b83a21eaSBrad Bishop 319b83a21eaSBrad Bishop auto& obj = oit->second; 320b83a21eaSBrad Bishop auto iit = obj.find(interface); 321b83a21eaSBrad Bishop if (iit == obj.end()) 322615b2a8fSBrad Bishop throw std::runtime_error("interface was not found"); 323b83a21eaSBrad Bishop 324150147aeSBrad Bishop return iit->second; 325b83a21eaSBrad Bishop } 326b83a21eaSBrad Bishop 327b28990f3SDeepak Kodihalli void Manager::restore() 328b28990f3SDeepak Kodihalli { 329e6b21c74SKun Yi namespace fs = std::filesystem; 330b28990f3SDeepak Kodihalli 331b28990f3SDeepak Kodihalli if (!fs::exists(fs::path(PIM_PERSIST_PATH))) 332b28990f3SDeepak Kodihalli { 333b28990f3SDeepak Kodihalli return; 334b28990f3SDeepak Kodihalli } 335b28990f3SDeepak Kodihalli 336b28990f3SDeepak Kodihalli static const std::string remove = 337b28990f3SDeepak Kodihalli std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT; 338b28990f3SDeepak Kodihalli 339b28990f3SDeepak Kodihalli std::map<sdbusplus::message::object_path, Object> objects; 340b28990f3SDeepak Kodihalli for (const auto& dirent : 341b28990f3SDeepak Kodihalli fs::recursive_directory_iterator(PIM_PERSIST_PATH)) 342b28990f3SDeepak Kodihalli { 343b28990f3SDeepak Kodihalli const auto& path = dirent.path(); 344b28990f3SDeepak Kodihalli if (fs::is_regular_file(path)) 345b28990f3SDeepak Kodihalli { 346b28990f3SDeepak Kodihalli auto ifaceName = path.filename().string(); 347b28990f3SDeepak Kodihalli auto objPath = path.parent_path().string(); 348b28990f3SDeepak Kodihalli objPath.erase(0, remove.length()); 349b28990f3SDeepak Kodihalli auto objit = objects.find(objPath); 350b28990f3SDeepak Kodihalli Interface propertyMap{}; 351b28990f3SDeepak Kodihalli if (objects.end() != objit) 352b28990f3SDeepak Kodihalli { 353b28990f3SDeepak Kodihalli auto& object = objit->second; 354b28990f3SDeepak Kodihalli object.emplace(std::move(ifaceName), std::move(propertyMap)); 355b28990f3SDeepak Kodihalli } 356b28990f3SDeepak Kodihalli else 357b28990f3SDeepak Kodihalli { 358b28990f3SDeepak Kodihalli Object object; 359b28990f3SDeepak Kodihalli object.emplace(std::move(ifaceName), std::move(propertyMap)); 360b28990f3SDeepak Kodihalli objects.emplace(std::move(objPath), std::move(object)); 361b28990f3SDeepak Kodihalli } 362b28990f3SDeepak Kodihalli } 363b28990f3SDeepak Kodihalli } 364b28990f3SDeepak Kodihalli if (!objects.empty()) 365b28990f3SDeepak Kodihalli { 366b28990f3SDeepak Kodihalli auto restoreFromCache = true; 367b28990f3SDeepak Kodihalli updateObjects(objects, restoreFromCache); 368b28990f3SDeepak Kodihalli } 369b28990f3SDeepak Kodihalli } 370b28990f3SDeepak Kodihalli 37149aefb31SBrad Bishop } // namespace manager 37249aefb31SBrad Bishop } // namespace inventory 37349aefb31SBrad Bishop } // namespace phosphor 37449aefb31SBrad Bishop 37549aefb31SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 376