24 #include <plugin/loader.h> 26 #include <utils/system/dynamic_module/module_manager.h> 27 #include <utils/system/dynamic_module/module.h> 46 class PluginLoader::Data
50 std::map< Plugin *, Module * > plugin_module_map;
51 std::map< std::string, Plugin * > name_plugin_map;
52 std::map< Plugin *, std::string > plugin_name_map;
64 PluginLoadException::PluginLoadException(
const char *plugin,
const char *message)
67 append(
"Plugin '%s' could not be loaded: %s", plugin, message);
85 append(
"Plugin '%s' could not be loaded: %s", plugin, message);
111 append(
"Plugin '%s' could not be unloaded", plugin_name);
131 plugin_base_dir_ = plugin_base_dir;
158 PluginLoader::open_module(
const char *plugin_name)
160 std::string module_name = std::string(plugin_name) +
"." + d_->mm->get_module_file_extension();
163 return d_->mm->open_module(module_name.c_str());
164 }
catch (ModuleOpenException &e) {
165 throw PluginLoadException(plugin_name,
"failed to open module", e);
171 PluginLoader::create_instance(
const char *plugin_name, Module *module)
173 if ( ! module->has_symbol(
"plugin_factory") ) {
174 throw PluginLoadException(plugin_name,
"Symbol 'plugin_factory' not found. Forgot EXPORT_PLUGIN?");
176 if ( ! module->has_symbol(
"plugin_description") ) {
177 throw PluginLoadException(plugin_name,
"Symbol 'plugin_description' not found. Forgot PLUGIN_DESCRIPTION?");
180 PluginFactoryFunc pff = (PluginFactoryFunc)module->get_symbol(
"plugin_factory");
185 throw PluginLoadException(plugin_name,
"Plugin could not be instantiated");
187 p->set_name(plugin_name);
213 std::string pn = plugin_name;
215 if ( d_->name_plugin_map.find(pn) != d_->name_plugin_map.end() ) {
216 return d_->name_plugin_map[pn];
220 Module *module = open_module(plugin_name);
221 Plugin *p = create_instance(plugin_name, module);
223 d_->plugin_module_map[p] = module;
224 d_->name_plugin_map[pn] = p;
225 d_->plugin_name_map[p] = pn;
242 PluginLoader::get_string_symbol(
const char *plugin_name,
243 const char *symbol_name,
const char *section_name)
246 GElf_Ehdr elf_header;
249 std::string module_name =
250 plugin_base_dir_ +
"/" + plugin_name +
"." + d_->mm->get_module_file_extension();
252 if(elf_version(EV_CURRENT) == EV_NONE) {
253 throw Exception(
"libelf library ELF version too old");
256 int fd = open(module_name.c_str(), O_RDONLY);
258 throw Exception(
"Failed to open file of plugin '%s'", plugin_name);
261 elf = elf_begin(fd, ELF_C_READ, NULL);
263 throw Exception(
"Cannot read elf file: %s", elf_errmsg(elf_errno()));
266 if (gelf_getehdr(elf, &elf_header) == NULL) {
268 throw Exception(
"Failed to read ELF header of plugin %s: %s",
269 plugin_name, elf_errmsg(elf_errno()));
273 while((scn = elf_nextscn(elf, scn)) != 0) {
275 gelf_getshdr(scn, &shdr);
277 if(shdr.sh_type == SHT_SYMTAB) {
278 Elf_Data *edata = elf_getdata(scn, NULL);
279 size_t symbol_count = shdr.sh_size / shdr.sh_entsize;
281 for(
size_t i = 0; i < symbol_count; ++i) {
283 gelf_getsym(edata, i, &sym);
286 Elf_Scn *sym_scn = elf_getscn(elf, sym.st_shndx);
287 gelf_getshdr(sym_scn, &sym_shdr);
289 char *secname = elf_strptr(elf, elf_header.e_shstrndx, sym_shdr.sh_name);
290 char *symname = elf_strptr(elf, shdr.sh_link, sym.st_name);
292 if ((strcmp(secname, section_name) == 0) &&
293 (strcmp(symname, symbol_name) == 0))
296 Elf_Data *sym_data = elf_rawdata(sym_scn, NULL);
298 (
const char *)sym_data->d_buf + (sym.st_value - sym_shdr.sh_offset);
299 const char *
const limit = start + sym.st_size;
300 const char *end = (
const char *)memchr(start,
'\0', limit - start);
304 std::string rv(start);
310 throw Exception(
"Failed to retrieve string for symbol '%s' in section '%s'" 311 " of plugin '%s'", symbol_name, section_name, plugin_name);
319 throw Exception(
"Description for plugin %s not found. " 320 "Forgot PLUGIN_DESCRIPTION?", plugin_name);
322 throw Exception(
"libelf not supported at compile time");
336 return get_string_symbol(plugin_name,
"_plugin_description");
338 Module *module = open_module(plugin_name);
340 if ( ! module->
has_symbol(
"plugin_description") ) {
341 throw PluginLoadException(plugin_name,
"Symbol 'plugin_description' not found. Forgot PLUGIN_DESCRIPTION?");
345 std::string rv = pdf();
346 d_->mm->close_module(module);
360 return ( d_->name_plugin_map.find(plugin_name) != d_->name_plugin_map.end() );
378 if ( d_->plugin_module_map.find(plugin) != d_->plugin_module_map.end() ) {
380 PluginDestroyFunc pdf = (PluginDestroyFunc)d_->plugin_module_map[plugin]->get_symbol(
"plugin_destroy");
384 d_->mm->close_module(d_->plugin_module_map[plugin]);
385 d_->plugin_module_map.erase(plugin);
387 d_->name_plugin_map.erase(d_->plugin_name_map[plugin]);
388 d_->plugin_name_map.erase(plugin);
PluginLoader(const char *plugin_base_dir, Configuration *config)
Constructor.
PluginUnloadException(const char *plugin_type, const char *add_msg=NULL)
Constructor.
Fawkes library namespace.
This exception is thrown if the requested plugin could not be loaded.
~PluginLoadException()
Destructor.
PluginLoadException(const char *plugin, const char *message)
Constructor.
void unload(Plugin *plugin)
Unload the given plugin This will unload the given plugin.
Dynamic module loader for Linux, FreeBSD, and MacOS X.
Base class for exceptions in Fawkes.
std::string get_description(const char *plugin_name)
Get plugin description.
const char *(* PluginDescriptionFunc)()
Plugin description function for the shared library.
std::string plugin_name() const
Get name of plugin which failed to load.
virtual void * get_symbol(const char *symbol_name)
Get a symbol from the module.
void copy_messages(const Exception &exc)
Copy messages from given exception.
ModuleManager * get_module_manager() const
Get module manager.
bool is_loaded(const char *plugin_name)
Check if a plugin is loaded.
~PluginLoader()
Destructor.
Interface for configuration handling.
void append(const char *format,...)
Append messages to the message list.
virtual bool has_symbol(const char *symbol_name)
Check if the module has the given symbol.
Plugin * load(const char *plugin_name)
Load a specific plugin The plugin loader is clever and guarantees that every plugin is only loaded on...