LCOV - code coverage report
Current view: top level - src/libs/elektra - backend.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 130 171 76.0 %
Date: 2019-09-12 12:28:41 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Everything related to a backend.
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #ifdef HAVE_KDBCONFIG_H
      10             : #include "kdbconfig.h"
      11             : #endif
      12             : 
      13             : #include <kdbassert.h>
      14             : 
      15             : #ifdef HAVE_LOCALE_H
      16             : #include <locale.h>
      17             : #endif
      18             : 
      19             : #ifdef HAVE_STDLIB_H
      20             : #include <stdlib.h>
      21             : #endif
      22             : 
      23             : #ifdef HAVE_STDARG_H
      24             : #include <stdarg.h>
      25             : #endif
      26             : 
      27             : #ifdef HAVE_CTYPE_H
      28             : #include <ctype.h>
      29             : #endif
      30             : 
      31             : #ifdef HAVE_STRING_H
      32             : #include <string.h>
      33             : #endif
      34             : 
      35             : #include <kdbinternal.h>
      36             : 
      37             : /**
      38             :  * @brief Allocate a backend
      39             :  *
      40             :  * Initialize everything with zero, except: sizes with -1
      41             :  * and refcounter with 1
      42             :  *
      43             :  * @return
      44             :  */
      45             : static Backend * elektraBackendAllocate (void)
      46             : {
      47       97143 :         Backend * backend = elektraCalloc (sizeof (struct _Backend));
      48             : 
      49       97143 :         backend->refcounter = 1;
      50             : 
      51       97143 :         backend->specsize = -1;
      52       97143 :         backend->dirsize = -1;
      53       97143 :         backend->usersize = -1;
      54       97143 :         backend->systemsize = -1;
      55             :         return backend;
      56             : }
      57             : 
      58             : 
      59             : /**
      60             :  * @brief sets mountpoint
      61             :  *
      62             :  * @param backend where the mountpoint should be set
      63             :  * @param elektraConfig the config where the mountpoint can be found
      64             :  * @param [out] errorKey the name also has the mountpoint set
      65             :  *
      66             :  * @pre ksCurrent() is root key
      67             :  * @post ksCurrent() is root key
      68             :  *
      69             :  * @retval -1 if no mountpoint is found or memory allocation problem
      70             :  * @retval 0 on success
      71             :  */
      72        7163 : int elektraBackendSetMountpoint (Backend * backend, KeySet * elektraConfig, Key * errorKey)
      73             : {
      74        7163 :         Key * root = ksCurrent (elektraConfig);
      75        7163 :         Key * searchMountpoint = keyDup (root);
      76        7163 :         keyAddBaseName (searchMountpoint, "mountpoint");
      77        7163 :         Key * foundMountpoint = ksLookup (elektraConfig, searchMountpoint, 0);
      78        7163 :         keyDel (searchMountpoint);
      79        7163 :         ksLookup (elektraConfig, root, 0); // reset ksCurrent()
      80             : 
      81        7163 :         if (!foundMountpoint)
      82             :         {
      83           0 :                 ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Could not find mountpoint within root %s", keyName (root));
      84           0 :                 return -1;
      85             :         }
      86             : 
      87        7163 :         backend->mountpoint = keyNew ("", KEY_VALUE, keyBaseName (root), KEY_END);
      88        7163 :         elektraKeySetName (backend->mountpoint, keyString (foundMountpoint), KEY_CASCADING_NAME | KEY_EMPTY_NAME);
      89             : 
      90        7163 :         keySetName (errorKey, keyName (backend->mountpoint));
      91             : 
      92        7163 :         if (!backend->mountpoint)
      93             :         {
      94           0 :                 ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Could not create mountpoint with name '%s' and value %s",
      95             :                                                    keyString (foundMountpoint), keyBaseName (root));
      96           0 :                 return -1;
      97             :         }
      98             : 
      99        7163 :         keyIncRef (backend->mountpoint);
     100        7163 :         return 0;
     101             : }
     102             : 
     103             : /**
     104             :  * Opens the internal backend that indicates that a backend
     105             :  * is missing at that place.
     106             :  *
     107             :  * @param global the global keyset of the KDB instance
     108             :  *
     109             :  * @return the fresh allocated backend or 0 if no memory
     110             :  */
     111           0 : static Backend * backendOpenMissing (KeySet * global, Key * mp)
     112             : {
     113           0 :         Backend * backend = elektraBackendAllocate ();
     114             : 
     115           0 :         Plugin * plugin = elektraPluginMissing ();
     116           0 :         if (!plugin)
     117             :         {
     118             :                 /* Could not allocate plugin */
     119           0 :                 elektraFree (backend);
     120           0 :                 return 0;
     121             :         }
     122           0 :         plugin->global = global;
     123             : 
     124           0 :         backend->getplugins[0] = plugin;
     125           0 :         backend->setplugins[0] = plugin;
     126           0 :         plugin->refcounter = 2;
     127             : 
     128           0 :         keySetString (mp, "missing");
     129           0 :         backend->mountpoint = mp;
     130           0 :         keyIncRef (backend->mountpoint);
     131             : 
     132           0 :         return backend;
     133             : }
     134             : 
     135             : /**Builds a backend out of the configuration supplied
     136             :  * from:
     137             :  *
     138             : @verbatim
     139             : system/elektra/mountpoints/<name>
     140             : @endverbatim
     141             :  *
     142             :  * The root key must be like the above example. You do
     143             :  * not need to rewind the keyset. But every key must be
     144             :  * below the root key.
     145             :  *
     146             :  * The internal consistency will be checked in this
     147             :  * function. If necessary parts are missing, like
     148             :  * no plugins, they cant be loaded or similar 0
     149             :  * will be returned.
     150             :  *
     151             :  * ksCut() is perfectly suitable for cutting out the
     152             :  * configuration like needed.
     153             :  *
     154             :  * @note The given KeySet will be deleted within the function,
     155             :  * don't use it afterwards.
     156             :  *
     157             :  * @param elektraConfig the configuration to work with.
     158             :  *        It is used to build up this backend.
     159             :  * @param modules used to load new modules or get references
     160             :  *        to existing one
     161             :  * @param global the global keyset of the KDB instance
     162             :  * @param errorKey the key where an error and warnings are added
     163             :  *
     164             :  * @return a pointer to a freshly allocated backend
     165             :  *         this could be the requested backend or a so called
     166             :  *         "missing backend".
     167             :  * @retval 0 if out of memory
     168             :  * @ingroup backend
     169             :  */
     170        7163 : Backend * backendOpen (KeySet * elektraConfig, KeySet * modules, KeySet * global, Key * errorKey)
     171             : {
     172             :         Key * cur;
     173        7163 :         KeySet * referencePlugins = 0;
     174        7163 :         KeySet * systemConfig = 0;
     175        7163 :         int failure = 0;
     176             : 
     177        7163 :         referencePlugins = ksNew (0, KS_END);
     178        7163 :         ksRewind (elektraConfig);
     179             : 
     180        7163 :         Key * root = ksNext (elektraConfig);
     181             : 
     182        7163 :         Backend * backend = elektraBackendAllocate ();
     183        7163 :         if (elektraBackendSetMountpoint (backend, elektraConfig, errorKey) == -1)
     184             :         { // warning already set
     185           0 :                 failure = 1;
     186             :         }
     187             : 
     188       42494 :         while ((cur = ksNext (elektraConfig)) != 0)
     189             :         {
     190       35331 :                 if (keyRel (root, cur) == 1)
     191             :                 {
     192             :                         // direct below root key
     193       35331 :                         KeySet * cut = ksCut (elektraConfig, cur);
     194       35331 :                         if (!strcmp (keyBaseName (cur), "config"))
     195             :                         {
     196        7043 :                                 systemConfig = elektraRenameKeys (cut, "system");
     197        7043 :                                 ksDel (cut);
     198             :                         }
     199       28288 :                         else if (!strcmp (keyBaseName (cur), "errorplugins"))
     200             :                         {
     201        7039 :                                 if (elektraProcessPlugins (backend->errorplugins, modules, referencePlugins, cut, systemConfig, global,
     202             :                                                            errorKey) == -1)
     203             :                                 {
     204           0 :                                         if (!failure)
     205           0 :                                                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey,
     206             :                                                                                   "Method 'elektraProcessPlugins' for error failed");
     207             :                                         failure = 1;
     208             :                                 }
     209             :                         }
     210       21249 :                         else if (!strcmp (keyBaseName (cur), "getplugins"))
     211             :                         {
     212        7043 :                                 if (elektraProcessPlugins (backend->getplugins, modules, referencePlugins, cut, systemConfig, global,
     213             :                                                            errorKey) == -1)
     214             :                                 {
     215           0 :                                         if (!failure)
     216           0 :                                                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey,
     217             :                                                                                   "Method 'elektraProcessPlugins' for get failed");
     218             :                                         failure = 1;
     219             :                                 }
     220             :                         }
     221       14206 :                         else if (!strcmp (keyBaseName (cur), "mountpoint"))
     222             :                         {
     223        7163 :                                 ksDel (cut); // already handled by elektraBackendSetMountpoint
     224        7163 :                                 continue;
     225             :                         }
     226        7043 :                         else if (!strcmp (keyBaseName (cur), "setplugins"))
     227             :                         {
     228        7043 :                                 if (elektraProcessPlugins (backend->setplugins, modules, referencePlugins, cut, systemConfig, global,
     229             :                                                            errorKey) == -1)
     230             :                                 {
     231           0 :                                         if (!failure)
     232           0 :                                                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey,
     233             :                                                                                   "Method 'elektraProcessPlugins' for set failed");
     234             :                                         failure = 1;
     235             :                                 }
     236             :                         }
     237             :                         else
     238             :                         {
     239             :                                 // no one cares about that config
     240           0 :                                 if (!failure)
     241           0 :                                         ELEKTRA_ADD_VALIDATION_SYNTACTIC_WARNINGF (
     242             :                                                 errorKey,
     243             :                                                 "Found garbage within the backend configuration. found: %s but expected config, "
     244             :                                                 "setplugins, getplugins, errorplugins or mountpoint",
     245             :                                                 keyBaseName (cur));
     246           0 :                                 ksDel (cut);
     247             :                         }
     248             :                 }
     249             :         }
     250             : 
     251        7163 :         if (failure)
     252             :         {
     253           0 :                 Backend * tmpBackend = backendOpenMissing (global, backend->mountpoint);
     254           0 :                 backendClose (backend, errorKey);
     255           0 :                 backend = tmpBackend;
     256             :         }
     257             : 
     258        7163 :         ksDel (systemConfig);
     259        7163 :         ksDel (elektraConfig);
     260        7163 :         ksDel (referencePlugins);
     261             : 
     262        7163 :         return backend;
     263             : }
     264             : 
     265             : /**
     266             :  * Opens a default backend using the plugin named KDB_RESOLVER
     267             :  * and KDB_STORAGE.
     268             :  *
     269             :  * @param modules the modules to work with
     270             :  * @param global the global keyset of the KDB instance
     271             :  * @param errorKey the key to issue warnings and errors to
     272             :  * @return the fresh allocated default backend or 0 if it failed
     273             :  */
     274       31630 : Backend * backendOpenDefault (KeySet * modules, KeySet * global, const char * file, Key * errorKey)
     275             : {
     276       31630 :         Backend * backend = elektraBackendAllocate ();
     277             : 
     278       31630 :         KeySet * resolverConfig = ksNew (5, keyNew ("system/path", KEY_VALUE, file, KEY_END), KS_END);
     279             : 
     280       31630 :         elektraKeySetName (errorKey, "", KEY_CASCADING_NAME | KEY_EMPTY_NAME);
     281             : 
     282       31630 :         Plugin * resolver = elektraPluginOpen (KDB_RESOLVER, modules, resolverConfig, errorKey);
     283       31630 :         if (!resolver)
     284             :         {
     285           0 :                 elektraFree (backend);
     286             :                 /* error already set in elektraPluginOpen */
     287           0 :                 return 0;
     288             :         }
     289       31630 :         resolver->global = global;
     290             : 
     291             : #ifdef ENABLE_TRACER
     292             :         KeySet * tracerConfig = ksNew (5,
     293             :                                        // does not matter because it is mounted differently in system/elektra/modules:
     294             :                                        // keyNew("system/logmodule", KEY_VALUE, "1", KEY_END),
     295             :                                        KS_END);
     296             :         Plugin * tracer = elektraPluginOpen ("tracer", modules, tracerConfig, errorKey);
     297             :         if (tracer)
     298             :         {
     299             :                 backend->getplugins[RESOLVER_PLUGIN + 1] = tracer;
     300             :                 backend->setplugins[RESOLVER_PLUGIN + 1] = tracer;
     301             :                 backend->errorplugins[RESOLVER_PLUGIN + 1] = tracer;
     302             :                 tracer->refcounter = 3;
     303             :                 tracer->global = global;
     304             :         }
     305             : #endif
     306             : 
     307       31630 :         backend->getplugins[RESOLVER_PLUGIN] = resolver;
     308       31630 :         backend->setplugins[RESOLVER_PLUGIN] = resolver;
     309       31630 :         backend->setplugins[COMMIT_PLUGIN] = resolver;
     310       31630 :         backend->errorplugins[STORAGE_PLUGIN] = resolver;
     311       31630 :         resolver->refcounter = 4;
     312             : 
     313       31630 :         KeySet * storageConfig = ksNew (5, KS_END);
     314             : 
     315       31630 :         Plugin * storage = elektraPluginOpen (KDB_STORAGE, modules, storageConfig, errorKey);
     316       31630 :         if (!storage)
     317             :         {
     318           0 :                 elektraPluginClose (resolver, errorKey);
     319           0 :                 elektraFree (backend);
     320             :                 /* error already set in elektraPluginOpen */
     321           0 :                 return 0;
     322             :         }
     323       31630 :         storage->global = global;
     324             : 
     325       31630 :         backend->getplugins[STORAGE_PLUGIN] = storage;
     326       31630 :         backend->setplugins[STORAGE_PLUGIN] = storage;
     327       31630 :         storage->refcounter = 2;
     328             : 
     329       31630 :         Key * mp = keyNew ("", KEY_VALUE, "default", KEY_END);
     330       31630 :         backend->mountpoint = mp;
     331       31630 :         keyIncRef (backend->mountpoint);
     332             : 
     333       31630 :         return backend;
     334             : }
     335             : 
     336             : /**@return a backend which gives plugin configuration of the module
     337             :  * which is currently point to.
     338             :  *
     339             :  * @param modules the modules to work with
     340             :  * @param global the global keyset of the KDB instance
     341             :  * @param errorKey the key to issue warnings and errors to
     342             :  */
     343       47827 : Backend * backendOpenModules (KeySet * modules, KeySet * global, Key * errorKey)
     344             : {
     345       47827 :         Backend * backend = elektraBackendAllocate ();
     346             : 
     347       47827 :         cursor_t save = ksGetCursor (modules);
     348       47827 :         KeySet * defaultConfig =
     349       47827 :                 ksNew (5, keyNew ("system/module", KEY_VALUE, "1", KEY_END), keyNew ("user/module", KEY_VALUE, "1", KEY_END), KS_END);
     350       47827 :         Key * cur = ksCurrent (modules);
     351             : 
     352       47827 :         elektraKeySetName (errorKey, keyName (cur), KEY_CASCADING_NAME | KEY_EMPTY_NAME);
     353             : 
     354       47827 :         Plugin * plugin = elektraPluginOpen (keyBaseName (cur), modules, defaultConfig, errorKey);
     355       47827 :         if (!plugin)
     356             :         {
     357             :                 /* Error already set in plugin */
     358           0 :                 elektraFree (backend);
     359           0 :                 return 0;
     360             :         }
     361       47827 :         plugin->global = global;
     362             : 
     363             : 
     364       47827 :         Key * mp = keyNew ("system/elektra/modules", KEY_VALUE, "modules", KEY_END);
     365             : 
     366             :         // for "virtual" plugins the keyBaseName (cur) would be "resolver" or "storage"
     367             :         // thus we use plugin->name here, which must be handled by kdbGet() of every
     368             :         // plugin properly by convention.
     369       47827 :         keyAddBaseName (mp, plugin->name);
     370             : 
     371       47827 :         backend->getplugins[0] = plugin;
     372       47827 :         plugin->refcounter = 1;
     373             : 
     374       47827 :         backend->mountpoint = mp;
     375       47827 :         keyIncRef (backend->mountpoint);
     376             : 
     377       47827 :         ksSetCursor (modules, save);
     378             : 
     379       47827 :         return backend;
     380             : }
     381             : 
     382             : /**
     383             :  * Opens the internal version backend.
     384             :  *
     385             :  * @param global the global keyset of the KDB instance
     386             :  * @param errorKey the key to issue warnings and errors to
     387             :  * @return the fresh allocated default backend or 0 if it failed
     388             :  */
     389       10523 : Backend * backendOpenVersion (KeySet * global, Key * errorKey ELEKTRA_UNUSED)
     390             : {
     391       10523 :         Backend * backend = elektraBackendAllocate ();
     392             : 
     393       10523 :         Plugin * plugin = elektraPluginVersion ();
     394       10523 :         if (!plugin)
     395             :         {
     396             :                 /* Could not allocate plugin */
     397           0 :                 elektraFree (backend);
     398           0 :                 return 0;
     399             :         }
     400       10523 :         plugin->global = global;
     401             : 
     402       10523 :         Key * mp = keyNew ("system/elektra/version", KEY_VALUE, "version", KEY_END);
     403             : 
     404       10523 :         backend->getplugins[0] = plugin;
     405       10523 :         backend->setplugins[0] = plugin;
     406       10523 :         plugin->refcounter = 2;
     407             : 
     408       10523 :         backend->mountpoint = mp;
     409       10523 :         keyIncRef (backend->mountpoint);
     410             : 
     411       10523 :         return backend;
     412             : }
     413             : 
     414             : 
     415             : /**
     416             :  * @brief Update internal size in backend
     417             :  *
     418             :  * @param backend the backend to update
     419             :  * @param parent for parent
     420             :  * @param size to update (-1 default, 0 empty, >0 otherwise)
     421             :  *
     422             :  * @pre parent must be serializable namespace
     423             :  *
     424             :  * @retval -1 if invalid parent (assert)
     425             :  * @retval 0 on success
     426             :  */
     427       85142 : int backendUpdateSize (Backend * backend, Key * parent, int size)
     428             : {
     429       85142 :         switch (keyGetNamespace (parent))
     430             :         {
     431             :         case KEY_NS_SPEC:
     432       14194 :                 backend->specsize = size;
     433       14194 :                 break;
     434             :         case KEY_NS_DIR:
     435       14116 :                 backend->dirsize = size;
     436       14116 :                 break;
     437             :         case KEY_NS_USER:
     438       16011 :                 backend->usersize = size;
     439       16011 :                 break;
     440             :         case KEY_NS_SYSTEM:
     441       40821 :                 backend->systemsize = size;
     442       40821 :                 break;
     443             :         case KEY_NS_PROC:
     444             :         case KEY_NS_EMPTY:
     445             :         case KEY_NS_META:
     446             :         case KEY_NS_CASCADING:
     447             :         case KEY_NS_NONE:
     448           0 :                 ELEKTRA_ASSERT (0, "invalid namespace %d", keyGetNamespace (parent));
     449             :                 return -1;
     450             :         }
     451             : 
     452             :         ELEKTRA_LOG_DEBUG ("spec: %zd", backend->specsize);
     453             :         ELEKTRA_LOG_DEBUG ("dir: %zd", backend->dirsize);
     454             :         ELEKTRA_LOG_DEBUG ("user: %zd", backend->usersize);
     455             :         ELEKTRA_LOG_DEBUG ("system: %zd", backend->systemsize);
     456             : 
     457             :         return 0;
     458             : }
     459             : 
     460      113952 : int backendClose (Backend * backend, Key * errorKey)
     461             : {
     462      113952 :         int errorOccurred = 0;
     463             : 
     464      113952 :         if (!backend) return -1;
     465             : 
     466      113926 :         --backend->refcounter;
     467             : 
     468             :         /* Check if we have the last reference on the backend (unsigned!) */
     469      113926 :         if (backend->refcounter > 0) return 0;
     470             : 
     471       97319 :         keyDecRef (backend->mountpoint);
     472       97319 :         keySetName (errorKey, keyName (backend->mountpoint));
     473       97319 :         keyDel (backend->mountpoint);
     474             : 
     475     1070509 :         for (int i = 0; i < NR_OF_PLUGINS; ++i)
     476             :         {
     477      973190 :                 int ret = elektraPluginClose (backend->setplugins[i], errorKey);
     478      973190 :                 if (ret == -1) ++errorOccurred;
     479             : 
     480      973190 :                 ret = elektraPluginClose (backend->getplugins[i], errorKey);
     481      973190 :                 if (ret == -1) ++errorOccurred;
     482             : 
     483      973190 :                 ret = elektraPluginClose (backend->errorplugins[i], errorKey);
     484      973190 :                 if (ret == -1) ++errorOccurred;
     485             :         }
     486       97319 :         elektraFree (backend);
     487             : 
     488       97319 :         if (errorOccurred)
     489             :                 return -1;
     490             :         else
     491       97319 :                 return 0;
     492             : }

Generated by: LCOV version 1.13