blob: 8ab7c9489edf82c87dbe6d1dd997e6a036354cd8 [file] [log] [blame]
Kevin Rocardee7ceed2013-07-05 10:56:27 +02001/*
David Wagnerb76c9d62014-02-05 18:30:24 +01002 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
Kevin Rocardee7ceed2013-07-05 10:56:27 +02004 *
David Wagnerb76c9d62014-02-05 18:30:24 +01005 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
Kevin Rocardee7ceed2013-07-05 10:56:27 +02007 *
David Wagnerb76c9d62014-02-05 18:30:24 +01008 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
Kevin Rocardee7ceed2013-07-05 10:56:27 +020010 *
David Wagnerb76c9d62014-02-05 18:30:24 +010011 * 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.
Patrick Benavoli68a91282011-08-31 11:23:23 +020029 */
30#include <dlfcn.h>
31#include <dirent.h>
Patrick Benavoliec0f84e2011-10-27 14:34:38 +020032#include <algorithm>
33#include <ctype.h>
Patrick Benavoli68a91282011-08-31 11:23:23 +020034#include "SystemClass.h"
35#include "SubsystemLibrary.h"
36#include "AutoLog.h"
Patrick Benavoli6ccab9d2011-11-10 23:21:01 +010037#include "VirtualSubsystem.h"
38#include "NamedElementBuilderTemplate.h"
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +010039#include <assert.h>
Guillaume Denneulina4ec15d2012-02-17 14:38:14 +010040#include "PluginLocation.h"
Kevin Rocardee7ceed2013-07-05 10:56:27 +020041#include "Utility.h"
Patrick Benavoli68a91282011-08-31 11:23:23 +020042
43#define base CConfigurableElement
44
Frédéric Boisnardd5679ac2013-07-31 17:40:57 +020045/**
46 * A plugin file name is of the form:
47 * lib<type>-subsystem.so or lib<type>-subsystem._host.so
48 *
49 * The plugin symbol is of the form:
50 * get<TYPE>SubsystemBuilder
51*/
Patrick Benavoliec0f84e2011-10-27 14:34:38 +020052// Plugin file naming
Frédéric Boisnardd5679ac2013-07-31 17:40:57 +020053const char* gpcPluginSuffix = "-subsystem";
54const char* gpcPluginPrefix = "lib";
Patrick Benavoliec0f84e2011-10-27 14:34:38 +020055
56// Plugin symbol naming
57const char* gpcPluginSymbolPrefix = "get";
Frédéric Boisnard487ce852013-07-19 17:17:52 +020058const char* gpcPluginSymbolSuffix = "SubsystemBuilder";
Patrick Benavoliec0f84e2011-10-27 14:34:38 +020059
Patrick Benavoli68a91282011-08-31 11:23:23 +020060// Used by subsystem plugins
Frédéric Boisnard487ce852013-07-19 17:17:52 +020061typedef void (*GetSubsystemBuilder)(CSubsystemLibrary*);
Patrick Benavoli68a91282011-08-31 11:23:23 +020062
Patrick Benavoli95ac0342011-11-07 20:32:51 +010063CSystemClass::CSystemClass() : _pSubsystemLibrary(new CSubsystemLibrary)
Patrick Benavoli68a91282011-08-31 11:23:23 +020064{
65}
66
67CSystemClass::~CSystemClass()
68{
69 delete _pSubsystemLibrary;
Renaud de Chivre1b8b3ca2013-12-13 15:09:44 +010070
71 // Close all previously opened libraries
72 while (!_subsystemLibraries.empty())
73 {
74 dlclose(_subsystemLibraries.back());
75 _subsystemLibraries.pop_back();
76 }
Patrick Benavoli68a91282011-08-31 11:23:23 +020077}
78
79bool CSystemClass::childrenAreDynamic() const
80{
81 return true;
82}
83
84string CSystemClass::getKind() const
85{
86 return "SystemClass";
87}
88
Kevin Rocardee7ceed2013-07-05 10:56:27 +020089bool CSystemClass::loadSubsystems(string& strError,
Kevin Rocard6be80352013-07-11 12:42:23 +020090 const CSubsystemPlugins* pSubsystemPlugins,
91 bool bVirtualSubsystemFallback)
Patrick Benavoli68a91282011-08-31 11:23:23 +020092{
Kevin Rocardee7ceed2013-07-05 10:56:27 +020093 CAutoLog autoLog_info(this, "Loading subsystem plugins");
Patrick Benavoli68a91282011-08-31 11:23:23 +020094
Kevin Rocard6be80352013-07-11 12:42:23 +020095 // Start clean
96 _pSubsystemLibrary->clean();
97
98 // Add virtual subsystem builder
99 _pSubsystemLibrary->addElementBuilder("Virtual",
100 new TNamedElementBuilderTemplate<CVirtualSubsystem>());
101 // Set virtual subsytem as builder fallback if required
102 _pSubsystemLibrary->enableDefaultMechanism(bVirtualSubsystemFallback);
103
104 // Add subsystem defined in shared libraries
105 list<string> lstrError;
106 bool bLoadPluginsSuccess = loadSubsystemsFromSharedLibraries(lstrError, pSubsystemPlugins);
107
108 if (bLoadPluginsSuccess) {
109 log_info("All subsystem plugins successfully loaded");
110 } else {
111 // Log plugin as warning if no fallback available
112 log_table(!bVirtualSubsystemFallback, lstrError);
113 }
114
115 if (!bVirtualSubsystemFallback) {
116 // Any problem reported is an error as there is no fallback.
117 // Fill strError for caller.
118 CUtility::asString(lstrError, strError);
119 }
120
121 return bLoadPluginsSuccess || bVirtualSubsystemFallback;
122}
123
124bool CSystemClass::loadSubsystemsFromSharedLibraries(list<string>& lstrError,
125 const CSubsystemPlugins* pSubsystemPlugins)
126{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200127 // Plugin list
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100128 list<string> lstrPluginFiles;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200129
Guillaume Denneulina4ec15d2012-02-17 14:38:14 +0100130 uint32_t uiPluginLocation;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200131
Guillaume Denneulina4ec15d2012-02-17 14:38:14 +0100132 for (uiPluginLocation = 0; uiPluginLocation < pSubsystemPlugins->getNbChildren(); uiPluginLocation++) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200133
Guillaume Denneulina4ec15d2012-02-17 14:38:14 +0100134 // Get Folder for current Plugin Location
135 const CPluginLocation* pPluginLocation = static_cast<const CPluginLocation*>(pSubsystemPlugins->getChild(uiPluginLocation));
Patrick Benavoli68a91282011-08-31 11:23:23 +0200136
Guillaume Denneulina4ec15d2012-02-17 14:38:14 +0100137 const string& strFolder = pPluginLocation->getFolder();
138
139 // Iterator on Plugin List:
140 list<string>::const_iterator it;
141
142 const list<string>& pluginList = pPluginLocation->getPluginList();
143
144 for (it = pluginList.begin(); it != pluginList.end(); ++it) {
145
146 // Fill Plugin files list
147 lstrPluginFiles.push_back(strFolder + "/" + *it);
148 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200149 }
150
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100151 // Actually load plugins
Kevin Rocard6be80352013-07-11 12:42:23 +0200152 while (!lstrPluginFiles.empty()) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200153
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100154 // Because plugins might depend on one another, loading will be done
155 // as an iteration process that finishes successfully when the remaining
156 // list of plugins to load gets empty or unsuccessfully if the loading
157 // process failed to load at least one of them
Patrick Benavoli68a91282011-08-31 11:23:23 +0200158
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100159 // Attempt to load the complete list
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200160 if (!loadPlugins(lstrPluginFiles, lstrError)) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200161
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200162 // Unable to load at least one plugin
163 break;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200164 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200165 }
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200166
Kevin Rocard6be80352013-07-11 12:42:23 +0200167 if (!lstrPluginFiles.empty()) {
168 // Unable to load at least one plugin
169 string strPluginUnloaded;
170 CUtility::asString(lstrPluginFiles, strPluginUnloaded, ", ");
171
Frédéric Boisnardecddaa32013-11-04 18:26:01 +0100172 lstrError.push_back("Unable to load the following plugins: " + strPluginUnloaded + ".");
Kevin Rocard6be80352013-07-11 12:42:23 +0200173 return false;
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200174 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200175
Kevin Rocard6be80352013-07-11 12:42:23 +0200176 return true;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200177}
178
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100179// Plugin symbol computation
180string CSystemClass::getPluginSymbol(const string& strPluginPath)
181{
182 // Extract plugin type out of file name
Frédéric Boisnardd5679ac2013-07-31 17:40:57 +0200183 string strPluginSuffix = gpcPluginSuffix;
184 string strPluginPrefix = gpcPluginPrefix;
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100185
Frédéric Boisnardd5679ac2013-07-31 17:40:57 +0200186 // Remove folder and library prefix
187 size_t iPluginTypePos = strPluginPath.rfind('/') + 1 + strPluginPrefix.length();
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100188
Frédéric Boisnardd5679ac2013-07-31 17:40:57 +0200189 // Get index of -subsystem.so or -subsystem_host.so suffix
190 size_t iSubsystemPos = strPluginPath.find(strPluginSuffix, iPluginTypePos);
191
192 // Get type (between iPluginTypePos and iSubsystemPos)
193 string strPluginType = strPluginPath.substr(iPluginTypePos, iSubsystemPos - iPluginTypePos);
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100194
195 // Make it upper case
196 std::transform(strPluginType.begin(), strPluginType.end(), strPluginType.begin(), ::toupper);
197
198 // Get plugin symbol
199 return gpcPluginSymbolPrefix + strPluginType + gpcPluginSymbolSuffix;
200}
201
202// Plugin loading
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200203bool CSystemClass::loadPlugins(list<string>& lstrPluginFiles, list<string>& lstrError)
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100204{
205 assert(lstrPluginFiles.size());
206
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200207 bool bAtLeastOneSubsystemPluginSuccessfullyLoaded = false;
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100208
209 list<string>::iterator it = lstrPluginFiles.begin();
210
211 while (it != lstrPluginFiles.end()) {
212
213 string strPluginFileName = *it;
214
Kevin Rocardace81f82012-12-11 16:19:17 +0100215 log_info("Attempting to load subsystem plugin path \"%s\"", strPluginFileName.c_str());
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100216
217 // Load attempt
218 void* lib_handle = dlopen(strPluginFileName.c_str(), RTLD_LAZY);
219
220 if (!lib_handle) {
221
Eduardo Mendi30095b32014-04-15 17:29:52 +0200222 const char *err = dlerror();
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100223 // Failed
Eduardo Mendi30095b32014-04-15 17:29:52 +0200224 if (err == NULL) {
225 lstrError.push_back("dlerror failed");
226 } else {
227 lstrError.push_back("Plugin load failed: " + string(err));
228 }
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100229 // Next plugin
230 ++it;
231
232 continue;
233 }
234
Renaud de Chivre1b8b3ca2013-12-13 15:09:44 +0100235 // Store libraries handles
236 _subsystemLibraries.push_back(lib_handle);
237
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100238 // Get plugin symbol
239 string strPluginSymbol = getPluginSymbol(strPluginFileName);
240
241 // Load symbol from library
Frédéric Boisnard487ce852013-07-19 17:17:52 +0200242 GetSubsystemBuilder pfnGetSubsystemBuilder = (GetSubsystemBuilder)dlsym(lib_handle, strPluginSymbol.c_str());
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100243
Frédéric Boisnard487ce852013-07-19 17:17:52 +0200244 if (!pfnGetSubsystemBuilder) {
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100245
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200246 lstrError.push_back("Subsystem plugin " + strPluginFileName +
247 " does not contain " + strPluginSymbol + " symbol.");
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100248
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200249 continue;
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100250 }
251
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200252 // Account for this success
253 bAtLeastOneSubsystemPluginSuccessfullyLoaded = true;
254
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100255 // Fill library
Frédéric Boisnard487ce852013-07-19 17:17:52 +0200256 pfnGetSubsystemBuilder(_pSubsystemLibrary);
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100257
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100258 // Remove successfully loaded plugin from list and select next
259 lstrPluginFiles.erase(it++);
260 }
261
Kevin Rocardee7ceed2013-07-05 10:56:27 +0200262 return bAtLeastOneSubsystemPluginSuccessfullyLoaded;
Patrick Benavoli9bed7ce2011-11-20 20:04:35 +0100263}
264
Patrick Benavoli68a91282011-08-31 11:23:23 +0200265const CSubsystemLibrary* CSystemClass::getSubsystemLibrary() const
266{
267 return _pSubsystemLibrary;
268}
269
Guillaume Denneulinf2fd15a2012-12-20 17:53:29 +0100270void CSystemClass::checkForSubsystemsToResync(CSyncerSet& syncerSet)
271{
272 uint32_t uiNbChildren = getNbChildren();
273 uint32_t uiChild;
274
275 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
276
277 CSubsystem* pSubsystem = static_cast<CSubsystem*>(getChild(uiChild));
278
279 // Collect and consume the need for a resync
280 if (pSubsystem->needResync(true)) {
281
282 log_info("Resynchronizing subsystem: %s", pSubsystem->getName().c_str());
283 // get all subsystem syncers
284 pSubsystem->fillSyncerSet(syncerSet);
285 }
286 }
287}
288
Kevin Rocard2fbe6e82013-03-26 17:09:29 +0100289void CSystemClass::cleanSubsystemsNeedToResync()
290{
291 uint32_t uiNbChildren = getNbChildren();
292 uint32_t uiChild;
293
294 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
295
296 CSubsystem* pSubsystem = static_cast<CSubsystem*>(getChild(uiChild));
297
298 // Consume the need for a resync
299 pSubsystem->needResync(true);
300 }
301}
302
Patrick Benavoli68a91282011-08-31 11:23:23 +0200303bool CSystemClass::init(string& strError)
304{
305 return base::init(strError);
306}
307
Georges-Henri Baron326a31d2012-06-28 12:05:09 +0200308// From IXmlSource
309void CSystemClass::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
310{
311 // Set the name of system class
312 xmlElement.setNameAttribute(getName());
313
314 base::toXml(xmlElement, serializingContext);
315}