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