blob: 6409c9be9267b79fc8407534b0db7b75dd02cfe9 [file] [log] [blame]
/* <auto_header>
* <FILENAME>
*
* INTEL CONFIDENTIAL
* Copyright © 2011 Intel
* Corporation All Rights Reserved.
*
* The source code contained or described herein and all documents related to
* the source code ("Material") are owned by Intel Corporation or its suppliers
* or licensors. Title to the Material remains with Intel Corporation or its
* suppliers and licensors. The Material contains trade secrets and proprietary
* and confidential information of Intel or its suppliers and licensors. The
* Material is protected by worldwide copyright and trade secret laws and
* treaty provisions. No part of the Material may be used, copied, reproduced,
* modified, published, uploaded, posted, transmitted, distributed, or
* disclosed in any way without Intel’s prior express written permission.
*
* No license under any patent, copyright, trade secret or other intellectual
* property right is granted to or conferred upon you by disclosure or delivery
* of the Materials, either expressly, by implication, inducement, estoppel or
* otherwise. Any license under such intellectual property rights must be
* express and approved by Intel in writing.
*
* AUTHOR: Patrick Benavoli (patrickx.benavoli@intel.com)
* CREATED: 2011-06-01
* UPDATED: 2011-07-27
*
*
* </auto_header>
*/
#include <dlfcn.h>
#include <dirent.h>
#include <algorithm>
#include <ctype.h>
#include "SystemClass.h"
#include "SubsystemLibrary.h"
#include "AutoLog.h"
#include "VirtualSubsystem.h"
#include "NamedElementBuilderTemplate.h"
#include <assert.h>
#define base CConfigurableElement
// A plugin file name is of the form:
// lib<type>-subsystem.so
// The plugin symbol is of the form:
// get<TYPE>SusbystemBuilder
// Plugin file naming
const char* gpcPluginPattern = "-subsystem.so";
const char* gpcLibraryPrefix = "lib";
// Plugin symbol naming
const char* gpcPluginSymbolPrefix = "get";
const char* gpcPluginSymbolSuffix = "SusbystemBuilder";
// Used by subsystem plugins
typedef void (*GetSusbystemBuilder)(CSubsystemLibrary*);
CSystemClass::CSystemClass() : _pSubsystemLibrary(new CSubsystemLibrary)
{
}
CSystemClass::~CSystemClass()
{
delete _pSubsystemLibrary;
}
bool CSystemClass::childrenAreDynamic() const
{
return true;
}
string CSystemClass::getKind() const
{
return "SystemClass";
}
bool CSystemClass::loadSubsystems(string& strError, const vector<string>& astrPluginFolderPaths)
{
CAutoLog autoLlog(this, "Loading subsystem plugins");
// Plugin list
list<string> lstrPluginFiles;
uint32_t uiFolderLocation;
for (uiFolderLocation = 0; uiFolderLocation < astrPluginFolderPaths.size(); uiFolderLocation++) {
// Folder for current SystemClass
string strPluginPath = astrPluginFolderPaths[uiFolderLocation] + "/";
// Get plugin list
getPluginFiles(strPluginPath, lstrPluginFiles);
}
// Check at least one subsystem plugin available
if (!lstrPluginFiles.size()) {
// No plugin found?
log("No subsystem plugin found");
// Don't bail out now that we have virtual subsystems
}
// Start clean
_pSubsystemLibrary->clean();
// Actually load plugins
while (lstrPluginFiles.size()) {
// Because plugins might depend on one another, loading will be done
// as an iteration process that finishes successfully when the remaining
// list of plugins to load gets empty or unsuccessfully if the loading
// process failed to load at least one of them
// Attempt to load the complete list
if (!loadPlugins(lstrPluginFiles, strError)) {
// Display the list of plugins we were unable to load
// Leave clean
_pSubsystemLibrary->clean();
return false;
}
}
log("All subsystem plugins successfully loaded");
// Add virtual subsystem builder
_pSubsystemLibrary->addElementBuilder(new TNamedElementBuilderTemplate<CVirtualSubsystem>("Virtual"));
return true;
}
// Subsystem plugins
bool CSystemClass::getPluginFiles(const string& strPluginPath, list<string>& lstrPluginFiles) const
{
log("Seeking subsystem plugins from folder \"%s\"", strPluginPath.c_str());
DIR *dirp;
struct dirent *dp;
if ((dirp = opendir(strPluginPath.c_str())) == NULL) {
return false;
}
const string strPluginPattern(gpcPluginPattern);
// Parse it and load plugins
while ((dp = readdir(dirp)) != NULL) {
string strFileName(dp->d_name);
// Check file name ends with pattern
size_t uiPatternPos = strFileName.rfind(strPluginPattern, -1);
if (uiPatternPos != (size_t)-1 && uiPatternPos == strFileName.size() - strPluginPattern.size()) {
// Found plugin
lstrPluginFiles.push_back(strPluginPath + strFileName);
}
}
// Close plugin folder
closedir(dirp);
return true;
}
// Plugin symbol computation
string CSystemClass::getPluginSymbol(const string& strPluginPath)
{
// Extract plugin type out of file name
string strPluginPattern = gpcPluginPattern;
string strLibraryPrefix = gpcLibraryPrefix;
// Remove folder
int32_t iSlashPos = strPluginPath.rfind('/') + 1 + strLibraryPrefix.length();
// Get type
string strPluginType = strPluginPath.substr(iSlashPos, strPluginPath.length() - iSlashPos - strPluginPattern.length());
// Make it upper case
std::transform(strPluginType.begin(), strPluginType.end(), strPluginType.begin(), ::toupper);
// Get plugin symbol
return gpcPluginSymbolPrefix + strPluginType + gpcPluginSymbolSuffix;
}
// Plugin loading
bool CSystemClass::loadPlugins(list<string>& lstrPluginFiles, string& strError)
{
assert(lstrPluginFiles.size());
bool bAtLeastOneSybsystemPluginSuccessfullyLoaded = false;
list<string>::iterator it = lstrPluginFiles.begin();
while (it != lstrPluginFiles.end()) {
string strPluginFileName = *it;
log("Attempting to load subsystem plugin path \"%s\"", strPluginFileName.c_str());
// Load attempt
void* lib_handle = dlopen(strPluginFileName.c_str(), RTLD_LAZY);
if (!lib_handle) {
// Failed
log("Plugin load failed: %s, proceeding on with remaining ones", dlerror());
// Next plugin
++it;
continue;
}
// Get plugin symbol
string strPluginSymbol = getPluginSymbol(strPluginFileName);
// Load symbol from library
GetSusbystemBuilder pfnGetSusbystemBuilder = (GetSusbystemBuilder)dlsym(lib_handle, strPluginSymbol.c_str());
if (!pfnGetSusbystemBuilder) {
strError = "Subsystem plugin " + strPluginFileName + " does not contain " + strPluginSymbol + " symbol.";
return false;
}
// Fill library
pfnGetSusbystemBuilder(_pSubsystemLibrary);
// Account for this success
bAtLeastOneSybsystemPluginSuccessfullyLoaded = true;
// Remove successfully loaded plugin from list and select next
lstrPluginFiles.erase(it++);
}
// Check for success
if (!bAtLeastOneSybsystemPluginSuccessfullyLoaded) {
// Return list of plugins we were unable to load
strError = "Unable to load the following plugins:\n";
for (it = lstrPluginFiles.begin(); it != lstrPluginFiles.end(); ++it) {
strError += *it + "\n";
}
return false;
}
return true;
}
const CSubsystemLibrary* CSystemClass::getSubsystemLibrary() const
{
return _pSubsystemLibrary;
}
bool CSystemClass::init(string& strError)
{
return base::init(strError);
}