// Copyright 2004-present Facebook. All Rights Reserved. #pragma once #include #include #include #include #include #include "osquery/registry/init_registry.h" #include "osquery/registry/singleton.h" namespace osquery { /** @brief A simple registry system for making values available by key across * components. * * To use this registry, make a header like so: * * @code{.cpp} * #include "osquery/registry.h" * * DECLARE_REGISTRY(MathFuncs, int, std::function) * #define REGISTERED_MATH_FUNCS REGISTRY(MathFuncs) * #define REGISTER_MATH_FUNC(id, func) \ * REGISTER(MathFuncs, id, func) * @endcode * * Client code may then advertise an entry from a .cpp like so: * * @code{.cpp} * #include "my/registry/header.h" * REGISTER_MATH_FUNC(1, sqrt); * @endcode * * Server code may then access the set of registered values by using * `REGISTERED_MATH_FUNCS` as a map, which will be populated after * `osquery::InitRegistry::get().run()` has been called. */ template class Registry : public std::unordered_map { public: /** @brief Register a value in the global registry * * This is used internally by the `DECLARE_REGISTRY` registration workflow. * If you're calling this method directly, you're probably doing something * incorrectly. */ void registerValue(const Key& key, const Value& value, const char* displayName = "registry") { if (this->insert(std::make_pair(key, value)).second) { VLOG(1) << displayName << "[" << key << "]" << " registered"; } else { LOG(ERROR) << displayName << "[" << key << "]" << " already registered"; } } }; } #define DECLARE_REGISTRY(registryName, KeyType, ObjectType) \ namespace osquery { \ namespace registries { \ class registryName : public Registry {}; \ } \ } #define REGISTRY(registryName) \ (osquery::Singleton::get()) #ifndef UNIQUE_VAR #define UNIQUE_VAR_CONCAT(_name_, _line_) _name_##_line_ #define UNIQUE_VAR_LINENAME(_name_, _line_) UNIQUE_VAR_CONCAT(_name_, _line_) #define UNIQUE_VAR(_name_) UNIQUE_VAR_LINENAME(_name_, __LINE__) #endif #define REGISTER(registryName, key, value) \ namespace {/* require global scope, don't pollute static namespace */ \ static osquery::RegisterInitFunc UNIQUE_VAR(registryName)([] { \ REGISTRY(registryName).registerValue((key), (value), #registryName); \ }); \ }