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
CSystemClass()66 CSystemClass::CSystemClass() : _pSubsystemLibrary(new CSubsystemLibrary)
67 {
68 }
69
~CSystemClass()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
childrenAreDynamic() const87 bool CSystemClass::childrenAreDynamic() const
88 {
89 return true;
90 }
91
getKind() const92 string CSystemClass::getKind() const
93 {
94 return "SystemClass";
95 }
96
loadSubsystems(string & strError,const CSubsystemPlugins * pSubsystemPlugins,bool bVirtualSubsystemFallback)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
loadSubsystemsFromSharedLibraries(list<string> & lstrError,const CSubsystemPlugins * pSubsystemPlugins)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
getPluginSymbol(const string & strPluginPath)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
loadPlugins(list<string> & lstrPluginFiles,list<string> & lstrError)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
getSubsystemLibrary() const275 const CSubsystemLibrary* CSystemClass::getSubsystemLibrary() const
276 {
277 return _pSubsystemLibrary;
278 }
279
checkForSubsystemsToResync(CSyncerSet & syncerSet)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
cleanSubsystemsNeedToResync()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