LCOV - code coverage report
Current view: top level - src/libs/loader - dl.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 41 54 75.9 %
Date: 2019-09-12 12:28:41 Functions: 3 3 100.0 %

          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             : }

Generated by: LCOV version 1.13