blob: 6459bbc47f71a58e955ca4ad8783d88633985cba [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cromo/plugin_manager.h"
#include <dirent.h>
#include <dlfcn.h>
#include <cerrno>
#include <cstring>
#include <base/logging.h>
#ifndef PLUGINDIR
#define PLUGINDIR "./plugins"
#endif
using std::string;
using std::vector;
vector<PluginManager::Plugin*> PluginManager::loaded_plugins_;
void PluginManager::LoadPlugins(CromoServer* server, const string& plugins) {
DIR* pdir = opendir(PLUGINDIR);
struct dirent* dirent;
if (!pdir) {
PLOG(ERROR) << "Cannot open plugin directory " PLUGINDIR;
return;
}
while ((dirent = readdir(pdir)) != nullptr) {
string leafname(dirent->d_name);
if (leafname.length() < 3 ||
leafname.substr(leafname.length()-3, string::npos) != ".so")
continue;
string filename(PLUGINDIR);
filename.append("/").append(leafname);
void* handle = dlopen(filename.c_str(), RTLD_LAZY);
if (!handle) {
LOG(ERROR) << "Cannot load plugin: " << dlerror();
continue;
}
cromo_plugin_descriptor* pdesc = reinterpret_cast<cromo_plugin_descriptor*>(
dlsym(handle, "plugin_descriptor"));
if (!pdesc) {
LOG(ERROR) << "Plugin does not contain descriptor: " << dlerror();
dlclose(handle);
continue;
}
if (plugins.size() == 0 ||
(pdesc->name && plugins.find(pdesc->name) != string::npos)) {
Plugin* pl = new Plugin;
pl->handle = handle;
pl->descriptor = pdesc;
pl->initted = false;
loaded_plugins_.push_back(pl);
LOG(INFO) << "Loaded plugin " << pdesc->name;
}
}
closedir(pdir);
vector<Plugin*>::const_iterator it;
for (it = loaded_plugins_.begin(); it != loaded_plugins_.end(); ++it) {
Plugin* pl = *it;
if (pl->descriptor->onload) {
pl->descriptor->onload(server);
pl->initted = true;
}
}
}
void PluginManager::UnloadPlugins(bool dlclose_plugins) {
vector<Plugin*>::const_iterator it;
for (it = loaded_plugins_.begin(); it != loaded_plugins_.end(); ++it) {
Plugin* pl = *it;
if (pl->initted && pl->descriptor->onunload) {
pl->descriptor->onunload();
}
}
// We do not always dlclose plugins if the process is about to exit
// anyway. Critical cleanup has already happpened by calling the
// onunload functions.
if (dlclose_plugins) {
for (it = loaded_plugins_.begin(); it != loaded_plugins_.end(); ++it) {
Plugin* pl = *it;
dlclose(pl->handle);
}
}
loaded_plugins_.erase(loaded_plugins_.begin(), loaded_plugins_.end());
}