Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Loading modules under linux.
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 :
8 : The name of the module will be libname.
9 : A .so will be appended.
10 : This file will be loaded.
11 :
12 : The path were the plugins are located,
13 : e.g. /usr/src/elektra
14 : need to be added with LD_LIBRARY_PATH.
15 :
16 : The reason is that only LD_LIBRARY_PATH
17 : also loads libraries which are seen by
18 : symlink only. That feature is needed for
19 : libelektra-default.
20 :
21 : The buildsystem makes sure that dlfcn.h
22 : exists.
23 : */
24 :
25 : #include <kdbconfig.h>
26 : #include <kdbmacros.h>
27 :
28 : #include <dlfcn.h>
29 :
30 : #include <kdberrors.h>
31 : #include <kdbmodule.h>
32 :
33 : #include <stdlib.h>
34 : #include <string.h>
35 :
36 : typedef struct _Module Module;
37 :
38 : struct _Module
39 : {
40 : void * handle;
41 : union
42 : {
43 : elektraPluginFactory f;
44 : void * v;
45 : } symbol;
46 : };
47 :
48 38545 : int elektraModulesInit (KeySet * modules, Key * error ELEKTRA_UNUSED)
49 : {
50 38545 : ksAppendKey (modules, keyNew ("system/elektra/modules", KEY_END));
51 :
52 38545 : return 0;
53 : }
54 :
55 190564 : elektraPluginFactory elektraModulesLoad (KeySet * modules, const char * name, Key * errorKey)
56 : {
57 : #ifdef _WIN32
58 : static const char elektraPluginPostfix[] = ".dll";
59 : #else
60 : static const char elektraPluginPostfix[] = ".so";
61 : #endif
62 :
63 190564 : Key * moduleKey = keyNew ("system/elektra/modules", KEY_END);
64 190564 : keyAddBaseName (moduleKey, name);
65 190564 : Key * lookup = ksLookup (modules, moduleKey, 0);
66 190564 : if (lookup)
67 : {
68 106788 : Module * module = (Module *) keyValue (lookup);
69 106788 : keyDel (moduleKey);
70 106788 : return module->symbol.f;
71 : }
72 :
73 83776 : char * moduleName = elektraMalloc (sizeof ("libelektra-") + strlen (name) + sizeof (elektraPluginPostfix) + 1);
74 :
75 83776 : strcpy (moduleName, "libelektra-");
76 83776 : strcat (moduleName, name);
77 83776 : strcat (moduleName, elektraPluginPostfix);
78 :
79 : Module module;
80 83776 : module.handle = dlopen (moduleName,
81 : #if DEBUG
82 : #ifdef RTLD_NODELETE
83 : RTLD_NODELETE |
84 : #endif
85 : #endif
86 : RTLD_NOW);
87 :
88 83776 : if (module.handle == NULL)
89 : {
90 20971 : ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Dlopen failed. Could not load module %s. Reason: %s", moduleName, dlerror ());
91 20971 : keyDel (moduleKey);
92 20971 : elektraFree (moduleName);
93 20971 : return 0;
94 : }
95 :
96 62805 : module.symbol.v = dlsym (module.handle, "elektraPluginSymbol");
97 62805 : if (module.symbol.v == NULL)
98 : {
99 0 : ELEKTRA_ADD_RESOURCE_WARNINGF (errorKey, "Dlsym failed. Could not get pointer to factory for module: %s. Reason: %s",
100 : moduleName, dlerror ());
101 0 : dlclose (module.handle);
102 0 : keyDel (moduleKey);
103 0 : elektraFree (moduleName);
104 0 : return 0;
105 : }
106 :
107 62805 : keySetBinary (moduleKey, &module, sizeof (Module));
108 62805 : ksAppendKey (modules, moduleKey);
109 62805 : elektraFree (moduleName);
110 :
111 62805 : return module.symbol.f;
112 : }
113 :
114 38477 : int elektraModulesClose (KeySet * modules, Key * errorKey)
115 : {
116 38477 : Key * root = ksLookupByName (modules, "system/elektra/modules", KDB_O_POP);
117 : Key * cur;
118 38477 : KeySet * newModules = 0;
119 38477 : int ret = 0;
120 :
121 38477 : if (!root)
122 : {
123 54 : ELEKTRA_ADD_INTERFACE_WARNING (errorKey, "Could not find root key system/elektra/modules");
124 54 : return -1;
125 : }
126 :
127 101120 : while ((cur = ksPop (modules)) != 0)
128 : {
129 62697 : Module * module = (Module *) keyValue (cur);
130 62697 : if (dlclose (module->handle) != 0)
131 : {
132 0 : if (ret != -1)
133 : {
134 : /* First failure, start saving handles where close did not work */
135 0 : newModules = ksNew (0, KS_END);
136 0 : ksAppendKey (newModules, root);
137 : }
138 0 : ret = -1;
139 0 : ELEKTRA_ADD_RESOURCE_WARNINGF (errorKey, "Could not close a module. Dlclose failed: %s", dlerror ());
140 :
141 0 : ksAppendKey (newModules, cur);
142 : }
143 : else
144 : {
145 62697 : keyDel (cur);
146 : }
147 : }
148 :
149 : /* Clear dlerror */
150 38423 : dlerror ();
151 :
152 38423 : if (ret == -1)
153 : {
154 0 : ksAppend (modules, newModules);
155 0 : ksDel (newModules);
156 : }
157 : else
158 : {
159 38423 : keyDel (root);
160 : }
161 :
162 : return ret;
163 : }
|