#include #include #include #include #include #include #include #include namespace fs = std::filesystem; namespace hk { namespace sense_api { struct DlCloser { void operator()(void* handle) const { if (handle) { dlclose(handle); } } }; static std::optional findLibraryPath( const std::string& libraryPath) { std::vector searchPaths = { fs::current_path().string(), fs::path("/proc/self/exe").parent_path().string() }; if (!OptionParser::getOptions().senseApiLibPath.empty()) { searchPaths.insert( searchPaths.begin(), OptionParser::getOptions().senseApiLibPath); } for (const auto& path : searchPaths) { fs::path fullPath = fs::path(path) / libraryPath; if (fs::exists(fullPath)) { return fullPath.string(); } } std::cerr << std::string(__func__) + ": library '" + libraryPath + "' isn't in search bespoke search paths: "; for (const auto& path : searchPaths) { std::cerr << path << " "; } std::cerr << std::endl; std::cerr << "Trying to load " + libraryPath + " from system default search " "paths\n"; return std::nullopt; } SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath) { const CSenseApiDesc *libApiDesc; std::optional fullPath = findLibraryPath(libraryPath); std::string resolvedPath = fullPath.value_or(libraryPath); // Clear any existing error dlerror(); auto dlopen_handle = std::unique_ptr( dlopen(resolvedPath.c_str(), RTLD_LAZY)); if (!dlopen_handle && fullPath.has_value()) { // Fallback to using the supplied libraryPath dlerror(); dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY)); } if (!dlopen_handle) { const char *dlerr = dlerror(); std::string error = (dlerr ? dlerr : "Unknown error while opening shlib"); throw std::runtime_error( std::string(__func__) + ": Cannot load library '" + libraryPath + "': " + error); } // Initialize getSenseApiDescriptor auto func = reinterpret_cast( dlsym(dlopen_handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR)); if (!func) { throw std::runtime_error( std::string(__func__) + ": dlsym('" HK_GET_SENSE_API_DESC_FN_NAME_STR "') failed for library '" + libraryPath + "'"); } libApiDesc = func(); if (!libApiDesc) { throw std::runtime_error( std::string(__func__) + ": getSenseApiDesc() returned NULL for " "library '" + libraryPath + "'"); } auto lib = std::make_unique( libraryPath, dlopen_handle.release(), func); lib->setSenseApiDesc(libApiDesc); senseApiLibs.push_back(std::move(lib)); return *senseApiLibs.back(); } std::optional> SenseApiManager::getSenseApiLib(const std::string& libraryPath) { auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(), [&libPath = libraryPath](const std::unique_ptr& lib) { return lib->libraryPath == libPath; } ); if (it != senseApiLibs.end()) { return **it; } return std::nullopt; } void SenseApiManager::unloadSenseApiLib(const std::string& libraryPath) { auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(), [&lpath = libraryPath](const std::unique_ptr& lib) { return lib->libraryPath == lpath; } ); if (it != senseApiLibs.end()) { senseApiLibs.erase(it); return; } std::cerr << std::string(__func__) + ": Library not found: " << libraryPath << '\n'; } void SenseApiManager::loadAllSenseApiLibsFromOptions() { const auto& options = OptionParser::getOptions(); for (const auto& libPath : options.senseApiLibs) { loadSenseApiLib(libPath); } } std::string SenseApiManager::stringifyLibs() const { std::string result; for (const auto& lib : senseApiLibs) { result += lib->stringify() + "\n"; } return result; } } // namespace sense_api } // namespace hk