Home | History | Annotate | Download | only in parameter
      1 /*
      2  * Copyright (c) 2011-2014, Intel Corporation
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation and/or
     13  * other materials provided with the distribution.
     14  *
     15  * 3. Neither the name of the copyright holder nor the names of its contributors
     16  * may be used to endorse or promote products derived from this software without
     17  * specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include <dlfcn.h>
     31 #include <dirent.h>
     32 #include <algorithm>
     33 #include <ctype.h>
     34 #include "SystemClass.h"
     35 #include "SubsystemLibrary.h"
     36 #include "AutoLog.h"
     37 #include "VirtualSubsystem.h"
     38 #include "NamedElementBuilderTemplate.h"
     39 #include <assert.h>
     40 #include "PluginLocation.h"
     41 #include "Utility.h"
     42 
     43 #define base CConfigurableElement
     44 
     45 using std::list;
     46 using std::string;
     47 
     48 /**
     49  * A plugin file name is of the form:
     50  * lib<type>-subsystem.so or lib<type>-subsystem._host.so
     51  *
     52  * The plugin symbol is of the form:
     53  * get<TYPE>SubsystemBuilder
     54 */
     55 // Plugin file naming
     56 const char* gpcPluginSuffix = "-subsystem";
     57 const char* gpcPluginPrefix = "lib";
     58 
     59 // Plugin symbol naming
     60 const char* gpcPluginSymbolPrefix = "get";
     61 const char* gpcPluginSymbolSuffix = "SubsystemBuilder";
     62 
     63 // Used by subsystem plugins
     64 typedef void (*GetSubsystemBuilder)(CSubsystemLibrary*);
     65 
     66 CSystemClass::CSystemClass() : _pSubsystemLibrary(new CSubsystemLibrary)
     67 {
     68 }
     69 
     70 CSystemClass::~CSystemClass()
     71 {
     72     delete _pSubsystemLibrary;
     73 
     74     // Destroy child subsystems *before* unloading the libraries (otherwise crashes will occur
     75     // as unmapped code will be referenced)
     76     clean();
     77 
     78     // Close all previously opened subsystem libraries
     79     list<void*>::const_iterator it;
     80 
     81     for (it = _subsystemLibraryHandleList.begin(); it != _subsystemLibraryHandleList.end(); ++it) {
     82 
     83         dlclose(*it);
     84     }
     85 }
     86 
     87 bool CSystemClass::childrenAreDynamic() const
     88 {
     89     return true;
     90 }
     91 
     92 string CSystemClass::getKind() const
     93 {
     94     return "SystemClass";
     95 }
     96 
     97 bool CSystemClass::loadSubsystems(string& strError,
     98                                   const CSubsystemPlugins* pSubsystemPlugins,
     99                                   bool bVirtualSubsystemFallback)
    100 {
    101     CAutoLog autoLog_info(this, "Loading subsystem plugins");
    102 
    103     // Start clean
    104     _pSubsystemLibrary->clean();
    105 
    106     // Add virtual subsystem builder
    107     _pSubsystemLibrary->addElementBuilder("Virtual",
    108                                           new TNamedElementBuilderTemplate<CVirtualSubsystem>());
    109     // Set virtual subsytem as builder fallback if required
    110     _pSubsystemLibrary->enableDefaultMechanism(bVirtualSubsystemFallback);
    111 
    112     // Add subsystem defined in shared libraries
    113     list<string> lstrError;
    114     bool bLoadPluginsSuccess = loadSubsystemsFromSharedLibraries(lstrError, pSubsystemPlugins);
    115 
    116     if (bLoadPluginsSuccess) {
    117         log_info("All subsystem plugins successfully loaded");
    118     } else {
    119         // Log plugin as warning if no fallback available
    120         log_table(!bVirtualSubsystemFallback, lstrError);
    121     }
    122 
    123     if (!bVirtualSubsystemFallback) {
    124         // Any problem reported is an error as there is no fallback.
    125         // Fill strError for caller.
    126         CUtility::asString(lstrError, strError);
    127     }
    128 
    129     return bLoadPluginsSuccess || bVirtualSubsystemFallback;
    130 }
    131 
    132 bool CSystemClass::loadSubsystemsFromSharedLibraries(list<string>& lstrError,
    133                                                      const CSubsystemPlugins* pSubsystemPlugins)
    134 {
    135     // Plugin list
    136     list<string> lstrPluginFiles;
    137 
    138     uint32_t uiPluginLocation;
    139 
    140     for (uiPluginLocation = 0; uiPluginLocation <  pSubsystemPlugins->getNbChildren(); uiPluginLocation++) {
    141 
    142         // Get Folder for current Plugin Location
    143         const CPluginLocation* pPluginLocation = static_cast<const CPluginLocation*>(pSubsystemPlugins->getChild(uiPluginLocation));
    144 
    145         string strFolder(pPluginLocation->getFolder());
    146         if (!strFolder.empty()) {
    147             strFolder += "/";
    148         }
    149         // Iterator on Plugin List:
    150         list<string>::const_iterator it;
    151 
    152         const list<string>& pluginList = pPluginLocation->getPluginList();
    153 
    154         for (it = pluginList.begin(); it != pluginList.end(); ++it) {
    155 
    156             // Fill Plugin files list
    157             lstrPluginFiles.push_back(strFolder + *it);
    158         }
    159     }
    160 
    161     // Actually load plugins
    162     while (!lstrPluginFiles.empty()) {
    163 
    164         // Because plugins might depend on one another, loading will be done
    165         // as an iteration process that finishes successfully when the remaining
    166         // list of plugins to load gets empty or unsuccessfully if the loading
    167         // process failed to load at least one of them
    168 
    169         // Attempt to load the complete list
    170         if (!loadPlugins(lstrPluginFiles, lstrError)) {
    171 
    172             // Unable to load at least one plugin
    173             break;
    174         }
    175     }
    176 
    177     if (!lstrPluginFiles.empty()) {
    178         // Unable to load at least one plugin
    179         string strPluginUnloaded;
    180         CUtility::asString(lstrPluginFiles, strPluginUnloaded, ", ");
    181 
    182         lstrError.push_back("Unable to load the following plugins: " + strPluginUnloaded + ".");
    183         return false;
    184     }
    185 
    186     return true;
    187 }
    188 
    189 // Plugin symbol computation
    190 string CSystemClass::getPluginSymbol(const string& strPluginPath)
    191 {
    192     // Extract plugin type out of file name
    193     string strPluginSuffix = gpcPluginSuffix;
    194     string strPluginPrefix = gpcPluginPrefix;
    195 
    196     // Remove folder and library prefix
    197     size_t iPluginTypePos = strPluginPath.rfind('/') + 1 + strPluginPrefix.length();
    198 
    199     // Get index of -subsystem.so or -subsystem_host.so suffix
    200     size_t iSubsystemPos = strPluginPath.find(strPluginSuffix, iPluginTypePos);
    201 
    202     // Get type (between iPluginTypePos and iSubsystemPos)
    203     string strPluginType = strPluginPath.substr(iPluginTypePos, iSubsystemPos - iPluginTypePos);
    204 
    205     // Make it upper case
    206     std::transform(strPluginType.begin(), strPluginType.end(), strPluginType.begin(), ::toupper);
    207 
    208     // Get plugin symbol
    209     return gpcPluginSymbolPrefix + strPluginType + gpcPluginSymbolSuffix;
    210 }
    211 
    212 // Plugin loading
    213 bool CSystemClass::loadPlugins(list<string>& lstrPluginFiles, list<string>& lstrError)
    214 {
    215     assert(lstrPluginFiles.size());
    216 
    217     bool bAtLeastOneSubsystemPluginSuccessfullyLoaded = false;
    218 
    219     list<string>::iterator it = lstrPluginFiles.begin();
    220 
    221     while (it != lstrPluginFiles.end()) {
    222 
    223         string strPluginFileName = *it;
    224 
    225         log_info("Attempting to load subsystem plugin path \"%s\"", strPluginFileName.c_str());
    226 
    227         // Load attempt
    228         void* lib_handle = dlopen(strPluginFileName.c_str(), RTLD_LAZY);
    229 
    230         if (!lib_handle) {
    231 
    232             const char *err = dlerror();
    233             // Failed
    234             if (err == NULL) {
    235                 lstrError.push_back("dlerror failed");
    236             } else {
    237                 lstrError.push_back("Plugin load failed: " + string(err));
    238             }
    239             // Next plugin
    240             ++it;
    241 
    242             continue;
    243         }
    244 
    245         // Store libraries handles
    246         _subsystemLibraryHandleList.push_back(lib_handle);
    247 
    248         // Get plugin symbol
    249         string strPluginSymbol = getPluginSymbol(strPluginFileName);
    250 
    251         // Load symbol from library
    252         GetSubsystemBuilder pfnGetSubsystemBuilder = (GetSubsystemBuilder)dlsym(lib_handle, strPluginSymbol.c_str());
    253 
    254         if (!pfnGetSubsystemBuilder) {
    255 
    256             lstrError.push_back("Subsystem plugin " + strPluginFileName +
    257                                 " does not contain " + strPluginSymbol + " symbol.");
    258 
    259             continue;
    260         }
    261 
    262         // Account for this success
    263         bAtLeastOneSubsystemPluginSuccessfullyLoaded = true;
    264 
    265         // Fill library
    266         pfnGetSubsystemBuilder(_pSubsystemLibrary);
    267 
    268         // Remove successfully loaded plugin from list and select next
    269         lstrPluginFiles.erase(it++);
    270     }
    271 
    272     return bAtLeastOneSubsystemPluginSuccessfullyLoaded;
    273 }
    274 
    275 const CSubsystemLibrary* CSystemClass::getSubsystemLibrary() const
    276 {
    277     return _pSubsystemLibrary;
    278 }
    279 
    280 void CSystemClass::checkForSubsystemsToResync(CSyncerSet& syncerSet)
    281 {
    282     size_t uiNbChildren = getNbChildren();
    283     size_t uiChild;
    284 
    285     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
    286 
    287         CSubsystem* pSubsystem = static_cast<CSubsystem*>(getChild(uiChild));
    288 
    289         // Collect and consume the need for a resync
    290         if (pSubsystem->needResync(true)) {
    291 
    292             log_info("Resynchronizing subsystem: %s", pSubsystem->getName().c_str());
    293             // get all subsystem syncers
    294             pSubsystem->fillSyncerSet(syncerSet);
    295         }
    296     }
    297 }
    298 
    299 void CSystemClass::cleanSubsystemsNeedToResync()
    300 {
    301     size_t uiNbChildren = getNbChildren();
    302     size_t uiChild;
    303 
    304     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
    305 
    306         CSubsystem* pSubsystem = static_cast<CSubsystem*>(getChild(uiChild));
    307 
    308         // Consume the need for a resync
    309         pSubsystem->needResync(true);
    310     }
    311 }
    312