LCOV - code coverage report
Current view: top level - src/libs/elektra - mount.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 228 265 86.0 %
Date: 2019-09-12 12:28:41 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Internals of mount functionality.
       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             : #if DEBUG && defined(HAVE_STDIO_H)
      14             : #include <stdio.h>
      15             : #endif
      16             : 
      17             : #ifdef HAVE_LOCALE_H
      18             : #include <locale.h>
      19             : #endif
      20             : 
      21             : #ifdef HAVE_STDLIB_H
      22             : #include <stdlib.h>
      23             : #endif
      24             : 
      25             : #ifdef HAVE_STRING_H
      26             : #include <string.h>
      27             : #endif
      28             : 
      29             : #ifdef HAVE_STDIO_H
      30             : #include <stdio.h>
      31             : #endif
      32             : 
      33             : #include <kdbassert.h>
      34             : 
      35             : #include "kdbinternal.h"
      36             : 
      37             : 
      38             : /**
      39             :  * Creates a trie from a given configuration.
      40             :  *
      41             :  * The config will be deleted within this function.
      42             :  *
      43             :  * @note mountDefault is not allowed to be executed before
      44             :  *
      45             :  * @param kdb the handle to work with
      46             :  * @param modules the current list of loaded modules
      47             :  * @param config the configuration which should be used to build up the trie.
      48             :  * @param errorKey the key used to report warnings
      49             :  * @retval -1 on failure
      50             :  * @retval 0 on success
      51             :  * @ingroup mount
      52             :  */
      53       10585 : int mountOpen (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey)
      54             : {
      55             :         Key * root;
      56             :         Key * cur;
      57             : 
      58       10585 :         ksRewind (config);
      59       10585 :         root = ksLookupByName (config, "system/elektra/mountpoints", KDB_O_CREATE);
      60             : 
      61       10585 :         int ret = 0;
      62       28329 :         while ((cur = ksNext (config)) != 0)
      63             :         {
      64        7159 :                 if (keyRel (root, cur) == 1)
      65             :                 {
      66        7159 :                         KeySet * cut = ksCut (config, cur);
      67        7159 :                         Backend * backend = backendOpen (cut, modules, kdb->global, errorKey);
      68             : 
      69        7159 :                         if (!backend)
      70             :                         {
      71           0 :                                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Could not create missing backend");
      72           0 :                                 ret = -1;
      73           0 :                                 continue;
      74             :                         }
      75             : 
      76        7159 :                         if (!backend->mountpoint)
      77             :                         {
      78           0 :                                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Backend has no mount point");
      79           0 :                                 ret = -1;
      80           0 :                                 backendClose (backend, errorKey);
      81           0 :                                 continue;
      82             :                         }
      83             : 
      84        7159 :                         if (mountBackend (kdb, backend, errorKey) == -1)
      85             :                         {
      86           0 :                                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Mounting of backend failed");
      87           0 :                                 ret = -1;
      88             :                                 /* mountBackend modified the refcounter. */
      89           0 :                                 backend->refcounter = 1;
      90           0 :                                 backendClose (backend, errorKey);
      91           0 :                                 continue;
      92             :                         }
      93             :                 }
      94             :         }
      95       10585 :         ksDel (config);
      96             : 
      97       10585 :         return ret;
      98             : }
      99             : 
     100             : 
     101             : /** Reopens the default backend and mounts the default backend if needed.
     102             :  *
     103             :  * @pre Default Backend is closed. mountOpen was executed before.
     104             :  *
     105             :  * @param kdb the handle to work with
     106             :  * @param modules the current list of loaded modules
     107             :  * @param errorKey the key used to report warnings
     108             :  * @retval -1 on error
     109             :  * @retval 0 on success
     110             :  * @ingroup mount
     111             :  */
     112       10577 : int mountDefault (KDB * kdb, KeySet * modules, int inFallback, Key * errorKey)
     113             : {
     114             :         // open the defaultBackend the first time
     115       10577 :         kdb->defaultBackend = backendOpenDefault (modules, kdb->global, KDB_DB_FILE, errorKey);
     116       10577 :         kdb->initBackend = 0;
     117             : 
     118       10577 :         if (!kdb->defaultBackend)
     119             :         {
     120           0 :                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Could not (re)open default backend");
     121           0 :                 return -1;
     122             :         }
     123             : 
     124       10577 :         if (!inFallback)
     125             :         {
     126             :                 /* Reopen the init Backend for fresh user experience (update issue) */
     127       10527 :                 kdb->initBackend = backendOpenDefault (modules, kdb->global, KDB_DB_INIT, errorKey);
     128             : 
     129       10527 :                 if (!kdb->initBackend)
     130             :                 {
     131           0 :                         ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Could not (re)open init backend");
     132           0 :                         return -1;
     133             :                 }
     134             :         }
     135             : 
     136             :         Key * key = 0;
     137             :         Backend * backend = 0;
     138             : 
     139       52885 :         for (elektraNamespace ns = KEY_NS_FIRST; ns <= KEY_NS_LAST; ++ns)
     140             :         {
     141       52885 :                 switch (ns)
     142             :                 {
     143             :                 case KEY_NS_SPEC:
     144       10577 :                         key = keyNew ("spec", KEY_VALUE, "default", KEY_END);
     145       10577 :                         backend = mountGetBackend (kdb, key);
     146       10577 :                         if (backend != kdb->defaultBackend)
     147             :                         {
     148             :                                 /* It does not matter that spec is not reachable anymore */
     149          18 :                                 keyDel (key);
     150             :                         }
     151             :                         else
     152             :                         {
     153             :                                 /* User is reachable, so append that to split */
     154       10559 :                                 splitAppend (kdb->split, backend, key, 2);
     155             :                         }
     156             :                         break;
     157             :                 case KEY_NS_DIR:
     158       10577 :                         key = keyNew ("dir", KEY_VALUE, "default", KEY_END);
     159       10577 :                         backend = mountGetBackend (kdb, key);
     160       10577 :                         if (backend != kdb->defaultBackend)
     161             :                         {
     162             :                                 /* It does not matter that dir is not reachable anymore */
     163          18 :                                 keyDel (key);
     164             :                         }
     165             :                         else
     166             :                         {
     167             :                                 /* Dir is reachable, so append that to split */
     168       10559 :                                 splitAppend (kdb->split, backend, key, 2);
     169             :                         }
     170             :                         break;
     171             :                 case KEY_NS_SYSTEM:
     172             :                         /* We want system/elektra still reachable
     173             :                          * through default backend.
     174             :                          * First check if it is still reachable.
     175             :                          */
     176       10577 :                         if (inFallback)
     177             :                         {
     178          50 :                                 key = keyNew (KDB_SYSTEM_ELEKTRA, KEY_END);
     179          50 :                                 backend = mountGetBackend (kdb, key);
     180          50 :                                 keyDel (key);
     181          50 :                                 if (backend != kdb->defaultBackend)
     182             :                                 {
     183             :                                         /* It is not reachable, mount it */
     184          24 :                                         mountBackend (kdb, kdb->defaultBackend, errorKey);
     185             :                                         /*mountBackend will set refcounter*/
     186          24 :                                         ++kdb->defaultBackend->refcounter;
     187          24 :                                         kdb->split->syncbits[kdb->split->size - 1] = 2;
     188             :                                 }
     189             :                                 else
     190             :                                 {
     191             :                                         /* Lets add the reachable default backend to split.
     192             :                                            Note that it is not possible that system/elektra has the default
     193             :                                            backend, but system has not. */
     194          26 :                                         splitAppend (kdb->split, backend, keyNew ("system", KEY_VALUE, "default", KEY_END), 2);
     195             :                                 }
     196             :                         }
     197             :                         else
     198             :                         {
     199             :                                 /* We want system/elektra still reachable
     200             :                                  * through bootstrap backend. */
     201       10527 :                                 mountBackend (kdb, kdb->initBackend, errorKey);
     202             :                                 /*mountBackend will set refcounter*/
     203       10527 :                                 ++kdb->initBackend->refcounter;
     204       10527 :                                 kdb->split->syncbits[kdb->split->size - 1] = 2;
     205             : 
     206       10527 :                                 key = keyNew ("system", KEY_VALUE, "default", KEY_END);
     207       10527 :                                 backend = mountGetBackend (kdb, key);
     208       10527 :                                 if (backend != kdb->defaultBackend)
     209             :                                 {
     210             :                                         /* It does not matter that system is not reachable anymore */
     211           2 :                                         keyDel (key);
     212             :                                 }
     213             :                                 else
     214             :                                 {
     215             :                                         /* System is reachable, so append that to split */
     216       10525 :                                         splitAppend (kdb->split, backend, key, 2);
     217             :                                 }
     218             :                         }
     219             :                         break;
     220             :                 case KEY_NS_USER:
     221       10577 :                         key = keyNew ("user", KEY_VALUE, "default", KEY_END);
     222       10577 :                         backend = mountGetBackend (kdb, key);
     223       10577 :                         if (backend != kdb->defaultBackend)
     224             :                         {
     225             :                                 /* It does not matter that user is not reachable anymore */
     226          24 :                                 keyDel (key);
     227             :                         }
     228             :                         else
     229             :                         {
     230             :                                 /* User is reachable, so append that to split */
     231       10553 :                                 splitAppend (kdb->split, backend, key, 2);
     232             :                         }
     233             :                         break;
     234             :                 case KEY_NS_EMPTY:
     235             :                 case KEY_NS_PROC:
     236             :                 case KEY_NS_NONE:
     237             :                 case KEY_NS_META:
     238             :                 case KEY_NS_CASCADING:
     239             :                         break;
     240             :                 }
     241             :         }
     242             : 
     243             :         return 0;
     244             : }
     245             : 
     246       31493 : KeySet * elektraMountGlobalsGetConfig (Key * cur, KeySet * global)
     247             : {
     248             :         // putting together the plugins configuration KeySet.
     249       31493 :         Key * sysConfigCutKey = keyDup (cur);
     250       31493 :         keyAddBaseName (sysConfigCutKey, "system");
     251       31493 :         Key * usrConfigCutKey = keyDup (cur);
     252       31493 :         keyAddBaseName (usrConfigCutKey, "user");
     253       31493 :         KeySet * sysConfigKS = ksCut (global, sysConfigCutKey);
     254       31493 :         KeySet * usrConfigKS = ksCut (global, usrConfigCutKey);
     255       31493 :         KeySet * renamedSysConfig = elektraRenameKeys (sysConfigKS, "system");
     256       31493 :         KeySet * renamedUsrConfig = elektraRenameKeys (usrConfigKS, "user");
     257       31493 :         ksDel (sysConfigKS);
     258       31493 :         ksDel (usrConfigKS);
     259       31493 :         keyDel (usrConfigCutKey);
     260       31493 :         keyDel (sysConfigCutKey);
     261       31493 :         KeySet * config = ksNew (0, KS_END);
     262       31493 :         ksAppend (config, renamedSysConfig);
     263       31493 :         ksAppend (config, renamedUsrConfig);
     264       31493 :         ksDel (renamedSysConfig);
     265       31493 :         ksDel (renamedUsrConfig);
     266             : 
     267       31493 :         return config;
     268             : }
     269             : 
     270      126086 : Key * elektraMountGlobalsFindPlugin (KeySet * referencePlugins, Key * cur)
     271             : {
     272             :         Key * refKey;
     273      126086 :         Key * searchKey = keyNew ("/", KEY_END);
     274      126086 :         keyAddBaseName (searchKey, keyString (cur));
     275      126086 :         refKey = ksLookup (referencePlugins, searchKey, 0);
     276      126086 :         keyDel (searchKey);
     277      126086 :         return refKey;
     278             : }
     279             : 
     280             : /**
     281             :  * Loads global plugin
     282             :  *
     283             :  * @retval -1 on failure
     284             :  * @retval 0 on empty plugin name (nothing configured at given position)
     285             :  * @retval 1 on success
     286             :  */
     287      126086 : int elektraMountGlobalsLoadPlugin (Plugin ** plugin, KeySet * referencePlugins, Key * cur, KeySet * global, KeySet * system,
     288             :                                    KeySet * modules, Key * errorKey)
     289             : {
     290      126086 :         Key * refKey = elektraMountGlobalsFindPlugin (referencePlugins, cur);
     291      126086 :         Key * openKey = keyDup (errorKey);
     292             : 
     293      126086 :         if (refKey)
     294             :         {
     295             :                 // plugin already loaded, just reference it
     296       94593 :                 *plugin = *(Plugin **) keyValue (refKey);
     297       94593 :                 (*plugin)->refcounter += 1;
     298             :         }
     299             :         else
     300             :         {
     301       31493 :                 KeySet * config = elektraMountGlobalsGetConfig (cur, global);
     302       31493 :                 ELEKTRA_NOT_NULL (config);
     303             :                 // config holds a newly allocated KeySet
     304       31493 :                 const char * pluginName = keyString (cur);
     305       31493 :                 if (!pluginName || pluginName[0] == '\0')
     306             :                 {
     307           0 :                         keyDel (openKey);
     308           0 :                         ksDel (config);
     309           0 :                         return 0;
     310             :                 }
     311             : 
     312             :                 // loading the new plugin
     313       31493 :                 *plugin = elektraPluginOpen (pluginName, modules, config, openKey);
     314       31493 :                 if (!(*plugin) && !elektraStrCmp (pluginName, "cache") && !ksLookupByName (system, "system/elektra/cache/enabled", 0))
     315             :                 {
     316       20970 :                         keyDel (openKey);
     317       20970 :                         return 0;
     318             :                 }
     319       10523 :                 else if (!(*plugin))
     320             :                 {
     321           0 :                         ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Could not load plugin '%s'", pluginName);
     322           0 :                         keyCopyAllMeta (errorKey, openKey);
     323           0 :                         keyDel (openKey);
     324           0 :                         return -1;
     325             :                 }
     326             : 
     327             :                 // saving the plugin reference to avoid having to load the plugin multiple times
     328       10523 :                 refKey = keyNew ("/", KEY_BINARY, KEY_SIZE, sizeof (Plugin *), KEY_VALUE, &(*plugin), KEY_END);
     329       10523 :                 keyAddBaseName (refKey, keyString (cur));
     330       10523 :                 ksAppendKey (referencePlugins, refKey);
     331       10523 :                 keyDel (refKey);
     332             :         }
     333             : 
     334      105116 :         keyCopyAllMeta (errorKey, openKey);
     335      105116 :         keyDel (openKey);
     336      105116 :         return 1;
     337             : }
     338             : 
     339       10485 : KeySet * elektraDefaultGlobalConfig (KeySet * keys)
     340             : {
     341       10485 :         KeySet * config = ksNew (
     342             :                 24, keyNew ("system/elektra/globalplugins", KEY_VALUE, "", KEY_END),
     343             :                 keyNew ("system/elektra/globalplugins/postcommit", KEY_VALUE, "list", KEY_END),
     344             :                 keyNew ("system/elektra/globalplugins/postcommit/user", KEY_VALUE, "list", KEY_END),
     345             :                 keyNew ("system/elektra/globalplugins/postcommit/user/placements", KEY_VALUE, "", KEY_END),
     346             :                 keyNew ("system/elektra/globalplugins/postcommit/user/placements/error", KEY_VALUE, "prerollback postrollback", KEY_END),
     347             :                 keyNew ("system/elektra/globalplugins/postcommit/user/placements/get", KEY_VALUE,
     348             :                         "pregetstorage procgetstorage postgetstorage", KEY_END),
     349             :                 keyNew ("system/elektra/globalplugins/postcommit/user/placements/set", KEY_VALUE, "presetstorage precommit postcommit",
     350             :                         KEY_END),
     351             : #ifndef __MINGW32__
     352             :                 keyNew ("system/elektra/globalplugins/postcommit/user/plugins", KEY_VALUE, "", KEY_END),
     353             :                 keyNew ("system/elektra/globalplugins/postcommit/user/plugins/#0", KEY_VALUE, "spec", KEY_END),
     354             :                 keyNew ("system/elektra/globalplugins/postcommit/user/plugins/#0/placements", KEY_VALUE, "spec", KEY_END),
     355             :                 keyNew ("system/elektra/globalplugins/postcommit/user/plugins/#0/placements/get", KEY_VALUE, "postgetstorage", KEY_END),
     356             :                 keyNew ("system/elektra/globalplugins/postcommit/user/plugins/#0/placements/set", KEY_VALUE, "presetstorage", KEY_END),
     357             : #endif
     358             :                 keyNew ("system/elektra/globalplugins/postgetcleanup", KEY_VALUE, "list", KEY_END),
     359             :                 keyNew ("system/elektra/globalplugins/postgetstorage", KEY_VALUE, "list", KEY_END),
     360             :                 keyNew ("system/elektra/globalplugins/postgetcache", KEY_VALUE, "", KEY_END),
     361             :                 keyNew ("system/elektra/globalplugins/postrollback", KEY_VALUE, "list", KEY_END),
     362             :                 keyNew ("system/elektra/globalplugins/precommit", KEY_VALUE, "list", KEY_END),
     363             :                 keyNew ("system/elektra/globalplugins/pregetstorage", KEY_VALUE, "list", KEY_END),
     364             :                 keyNew ("system/elektra/globalplugins/pregetcache", KEY_VALUE, "", KEY_END),
     365             :                 keyNew ("system/elektra/globalplugins/prerollback", KEY_VALUE, "list", KEY_END),
     366             :                 keyNew ("system/elektra/globalplugins/presetcleanup", KEY_VALUE, "list", KEY_END),
     367             :                 keyNew ("system/elektra/globalplugins/presetstorage", KEY_VALUE, "list", KEY_END),
     368             :                 keyNew ("system/elektra/globalplugins/procgetstorage", KEY_VALUE, "list", KEY_END), KS_END);
     369             : 
     370       10485 :         Key * cacheEnabled = ksLookupByName (keys, "system/elektra/cache/enabled", 0);
     371       10485 :         if (!cacheEnabled || (cacheEnabled && !elektraStrCmp (keyString (cacheEnabled), "1")))
     372             :         {
     373       10485 :                 ksAppendKey (config, keyNew ("system/elektra/globalplugins/postgetcache", KEY_VALUE, "cache", KEY_END));
     374       10485 :                 ksAppendKey (config, keyNew ("system/elektra/globalplugins/pregetcache", KEY_VALUE, "cache", KEY_END));
     375             :         }
     376             : 
     377       10485 :         return config;
     378             : }
     379             : 
     380       10523 : int mountGlobals (KDB * kdb, KeySet * keys, KeySet * modules, Key * errorKey)
     381             : {
     382       10523 :         int retval = 0;
     383       10523 :         Key * root = ksLookupByName (keys, "system/elektra/globalplugins", 0);
     384       10523 :         KeySet * system = ksDup (keys);
     385       10523 :         if (!root)
     386             :         {
     387             :                 ELEKTRA_LOG ("no global configuration, assuming spec as default");
     388       10485 :                 KeySet * tmp = keys;
     389       10485 :                 keys = elektraDefaultGlobalConfig (keys);
     390       10485 :                 ksDel (tmp);
     391       10485 :                 root = ksHead (keys);
     392             :         }
     393       10523 :         memset (kdb->globalPlugins, 0, NR_GLOBAL_POSITIONS * NR_GLOBAL_SUBPOSITIONS * sizeof (Plugin *));
     394             : 
     395       10523 :         KeySet * global = ksCut (keys, root);
     396             :         Key * cur;
     397       10523 :         KeySet * referencePlugins = ksNew (0, KS_END);
     398      157655 :         while ((cur = ksNext (global)) != NULL)
     399             :         {
     400             :                 // the cutpoints for the plugin configs are always directly below the "root", ignore everything else
     401      136609 :                 if (keyRel (root, cur) != 1) continue;
     402             : 
     403      126086 :                 char * placement = elektraStrDup (keyBaseName (cur));
     404             : 
     405     2395634 :                 for (GlobalpluginPositions i = 0; i < NR_GLOBAL_POSITIONS; ++i)
     406             :                 {
     407     2269548 :                         if (!elektraStrCaseCmp (placement, GlobalpluginPositionsStr[i]))
     408             :                         {
     409             : #if DEBUG && VERBOSE
     410             :                                 printf ("mounting global plugin %s to %s\n", pluginName, placement);
     411             : #endif
     412             :                                 // load plugins in implicit max once placement
     413      126086 :                                 Plugin * plugin = 0;
     414      126086 :                                 int mountRet =
     415             :                                         elektraMountGlobalsLoadPlugin (&plugin, referencePlugins, cur, global, system, modules, errorKey);
     416             : 
     417      126086 :                                 if (mountRet == -1)
     418             :                                         retval = -1; // error loading plugin
     419      126086 :                                 else if (mountRet == 0)
     420       20970 :                                         continue; // no plugin configured here
     421             :                                 else
     422             :                                 {
     423      105116 :                                         kdb->globalPlugins[i][MAXONCE] = plugin;
     424             :                                         // set handle to global keyset
     425      105116 :                                         plugin->global = kdb->global;
     426             :                                 }
     427             : 
     428             :                                 // load plugins in explicit placements
     429      105116 :                                 const char * placementName = keyName (cur);
     430      105116 :                                 Key * placementKey = ksLookupByName (global, placementName, 0);
     431      105116 :                                 KeySet * subPositions = ksCut (global, placementKey);
     432             :                                 Key * curSubPosition;
     433      315348 :                                 while ((curSubPosition = ksNext (subPositions)) != NULL)
     434             :                                 {
     435      105116 :                                         if (keyRel (placementKey, curSubPosition) != 1) continue;
     436           0 :                                         const char * subPlacement = keyBaseName (curSubPosition);
     437             : 
     438           0 :                                         for (GlobalpluginSubPositions j = 0; j < NR_GLOBAL_SUBPOSITIONS; ++j)
     439             :                                         {
     440           0 :                                                 if (j == MAXONCE) continue;
     441             : 
     442           0 :                                                 if (!elektraStrCaseCmp (subPlacement, GlobalpluginSubPositionsStr[j]))
     443             :                                                 {
     444           0 :                                                         Plugin * subPlugin = 0;
     445           0 :                                                         int subRet =
     446             :                                                                 elektraMountGlobalsLoadPlugin (&subPlugin, referencePlugins, curSubPosition,
     447             :                                                                                                subPositions, system, modules, errorKey);
     448           0 :                                                         if (subRet == -1)
     449             :                                                                 retval = -1; // error loading plugin
     450           0 :                                                         else if (subRet == 0)
     451           0 :                                                                 continue; // no plugin configured here
     452             :                                                         else
     453             :                                                         {
     454           0 :                                                                 kdb->globalPlugins[i][j] = subPlugin;
     455             :                                                                 // set handle to global keyset
     456           0 :                                                                 subPlugin->global = kdb->global;
     457             :                                                         }
     458             :                                                 }
     459             :                                         }
     460             :                                 }
     461      105116 :                                 ksDel (subPositions);
     462             :                         }
     463             :                 }
     464      126086 :                 elektraFree (placement);
     465             :         }
     466       10523 :         ksDel (global);
     467       10523 :         ksDel (keys);
     468       10523 :         ksDel (referencePlugins);
     469       10523 :         ksDel (system);
     470       10523 :         return retval;
     471             : }
     472             : 
     473             : /** Mount all module configurations.
     474             :  *
     475             :  * @param kdb the handle to work with
     476             :  * @param modules the current list of loaded modules
     477             :  * @param errorKey the key used to report warnings
     478             :  * @ingroup mount
     479             :  * @retval -1 if not rootkey was found
     480             :  * @retval 0 otherwise
     481             :  */
     482       10527 : int mountModules (KDB * kdb, KeySet * modules, Key * errorKey)
     483             : {
     484             :         Key * root;
     485             :         Key * cur;
     486             : 
     487       10527 :         root = ksLookupByName (modules, "system/elektra/modules", 0);
     488             : 
     489       10527 :         if (!root)
     490             :         {
     491           0 :                 ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "No root key found for modules");
     492           0 :                 return -1;
     493             :         }
     494             : 
     495       10527 :         KeySet * alreadyMounted = ksNew (5, KS_END);
     496       10527 :         ssize_t oldSize = 0;
     497             : 
     498       68881 :         while ((cur = ksNext (modules)) != 0)
     499             :         {
     500       47827 :                 Backend * backend = backendOpenModules (modules, kdb->global, errorKey);
     501             : 
     502       47827 :                 if (!backend)
     503             :                 {
     504             :                         // error already set in errorKey
     505           0 :                         continue;
     506             :                 }
     507             : 
     508       47827 :                 ksAppendKey (alreadyMounted, backend->mountpoint);
     509       47827 :                 if (ksGetSize (alreadyMounted) == oldSize)
     510             :                 {
     511             :                         // we already mounted that before
     512        4816 :                         backendClose (backend, errorKey);
     513        4816 :                         continue;
     514             :                 }
     515       43011 :                 ++oldSize;
     516       43011 :                 mountBackend (kdb, backend, errorKey);
     517             :         }
     518             : 
     519       10527 :         ksDel (alreadyMounted);
     520             : 
     521       10527 :         return 0;
     522             : }
     523             : 
     524             : /** Mount the version backend
     525             :  *
     526             :  * @param kdb the handle to work with
     527             :  * @param errorKey the key used to report warnings
     528             :  * @ingroup mount
     529             :  * @retval 0 on success
     530             :  */
     531       10523 : int mountVersion (KDB * kdb, Key * errorKey)
     532             : {
     533       10523 :         Backend * backend = backendOpenVersion (kdb->global, errorKey);
     534       10523 :         mountBackend (kdb, backend, errorKey);
     535             : 
     536       10523 :         return 0;
     537             : }
     538             : 
     539             : /**
     540             :  * Mounts a backend into the trie.
     541             :  *
     542             :  * @pre user must pass correctly allocated backend
     543             :  * @post sets reference counter of backend
     544             :  *
     545             :  * @warning in case of init and default backends, the reference counter needs to
     546             :  * be modified *after* calling mountBackend.
     547             :  *
     548             :  * @param kdb the handle to work with
     549             :  * @param backend the backend to mount
     550             :  * @param errorKey the key used to report warnings
     551             :  * @retval -1 on failure
     552             :  * @retval 1 on success
     553             :  * @ingroup mount
     554             :  */
     555       71248 : int mountBackend (KDB * kdb, Backend * backend, Key * errorKey ELEKTRA_UNUSED)
     556             : {
     557             : 
     558             :         char * mountpoint;
     559             :         /* 20 is enough for any of the combinations below. */
     560       71248 :         mountpoint = elektraMalloc (keyGetNameSize (backend->mountpoint) + 20);
     561             : 
     562             :         /* Note that you must set the refcounter to the number of insertions
     563             :            into the trie */
     564             : 
     565       71248 :         if (!strcmp (keyName (backend->mountpoint), ""))
     566             :         {
     567             :                 /* Default backend */
     568       10553 :                 sprintf (mountpoint, "system/elektra/");
     569       10553 :                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     570       10553 :                 splitAppend (kdb->split, backend, keyNew ("system/elektra/", KEY_VALUE, "default", KEY_END), 0);
     571       10553 :                 backend->refcounter = 1;
     572             :         }
     573       60695 :         else if (!strcmp (keyName (backend->mountpoint), "/"))
     574             :         {
     575             :                 /* Root backend */
     576          28 :                 backend->refcounter = 0;
     577         168 :                 for (elektraNamespace ns = KEY_NS_FIRST; ns <= KEY_NS_LAST; ++ns)
     578             :                 {
     579         140 :                         switch (ns)
     580             :                         {
     581             :                         case KEY_NS_SPEC:
     582          28 :                                 sprintf (mountpoint, "spec%s", keyName (backend->mountpoint));
     583          28 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     584          28 :                                 splitAppend (kdb->split, backend, keyNew ("spec", KEY_VALUE, "root", KEY_END), 2);
     585          28 :                                 ++backend->refcounter;
     586          28 :                                 break;
     587             :                         case KEY_NS_DIR:
     588          28 :                                 sprintf (mountpoint, "dir%s", keyName (backend->mountpoint));
     589          28 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     590          28 :                                 splitAppend (kdb->split, backend, keyNew ("dir", KEY_VALUE, "root", KEY_END), 2);
     591          28 :                                 ++backend->refcounter;
     592          28 :                                 break;
     593             :                         case KEY_NS_USER:
     594          28 :                                 sprintf (mountpoint, "user%s", keyName (backend->mountpoint));
     595          28 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     596          28 :                                 splitAppend (kdb->split, backend, keyNew ("user", KEY_VALUE, "root", KEY_END), 2);
     597          28 :                                 ++backend->refcounter;
     598          28 :                                 break;
     599             :                         case KEY_NS_SYSTEM:
     600          28 :                                 sprintf (mountpoint, "system%s", keyName (backend->mountpoint));
     601          28 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     602          28 :                                 splitAppend (kdb->split, backend, keyNew ("system", KEY_VALUE, "root", KEY_END), 2);
     603          28 :                                 ++backend->refcounter;
     604          28 :                                 break;
     605             :                         case KEY_NS_PROC:
     606             :                         case KEY_NS_EMPTY:
     607             :                         case KEY_NS_NONE:
     608             :                         case KEY_NS_META:
     609             :                         case KEY_NS_CASCADING:
     610             :                                 break;
     611             :                         }
     612             :                 }
     613             :         }
     614       60667 :         else if (keyName (backend->mountpoint)[0] == '/')
     615             :         {
     616             :                 /* Cascading Backend */
     617        2986 :                 backend->refcounter = 0;
     618       17916 :                 for (elektraNamespace ns = KEY_NS_FIRST; ns <= KEY_NS_LAST; ++ns)
     619             :                 {
     620       14930 :                         switch (ns)
     621             :                         {
     622             :                         case KEY_NS_DIR:
     623        2986 :                                 sprintf (mountpoint, "dir%s/", keyName (backend->mountpoint));
     624        2986 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     625        2986 :                                 splitAppend (kdb->split, backend, keyNew (mountpoint, KEY_VALUE, keyString (backend->mountpoint), KEY_END),
     626             :                                              2);
     627        2986 :                                 ++backend->refcounter;
     628        2986 :                                 break;
     629             :                         case KEY_NS_USER:
     630        2986 :                                 sprintf (mountpoint, "user%s/", keyName (backend->mountpoint));
     631        2986 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     632        2986 :                                 splitAppend (kdb->split, backend, keyNew (mountpoint, KEY_VALUE, keyString (backend->mountpoint), KEY_END),
     633             :                                              2);
     634        2986 :                                 ++backend->refcounter;
     635        2986 :                                 break;
     636             :                         case KEY_NS_SYSTEM:
     637        2986 :                                 sprintf (mountpoint, "system%s/", keyName (backend->mountpoint));
     638        2986 :                                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     639        2986 :                                 splitAppend (kdb->split, backend, keyNew (mountpoint, KEY_VALUE, keyString (backend->mountpoint), KEY_END),
     640             :                                              2);
     641        2986 :                                 ++backend->refcounter;
     642        2986 :                                 break;
     643             :                         case KEY_NS_SPEC:
     644             :                         // excluded on purpose because mounting spec is a separate step
     645             :                         // (see specmount)
     646             :                         case KEY_NS_EMPTY:
     647             :                         case KEY_NS_PROC:
     648             :                         case KEY_NS_NONE:
     649             :                         case KEY_NS_META:
     650             :                         case KEY_NS_CASCADING:
     651             :                                 break;
     652             :                         }
     653             :                 }
     654             :         }
     655             :         else
     656             :         {
     657             :                 /* Common single mounted backend */
     658       57681 :                 sprintf (mountpoint, "%s/", keyName (backend->mountpoint));
     659       57681 :                 kdb->trie = trieInsert (kdb->trie, mountpoint, backend);
     660       57681 :                 splitAppend (kdb->split, backend, keyDup (backend->mountpoint), 0);
     661       57681 :                 backend->refcounter = 1;
     662             :         }
     663             : 
     664       71248 :         elektraFree (mountpoint);
     665             : 
     666       71248 :         return 1;
     667             : }
     668             : 
     669             : 
     670             : /**
     671             :  * Lookup a mountpoint in a handle for a specific key.
     672             :  *
     673             :  * Will return a key representing the mountpoint or null
     674             :  * if there is no appropriate mountpoint e.g. its the
     675             :  * root mountpoint.
     676             :  *
     677             :  * @par Example:
     678             :  * @code
     679             : Key * key = keyNew ("system/template");
     680             : KDB * handle = kdbOpen();
     681             : Key *mountpoint=0;
     682             : mountpoint=kdbGetMountpoint(handle, key);
     683             : 
     684             : printf("The backend I am using is %s mounted in %s\n",
     685             :         keyValue(mountpoint),
     686             :         keyName(mountpoint));
     687             : kdbClose (handle);
     688             : keyDel (key);
     689             :  * @endcode
     690             :  *
     691             :  *
     692             :  * @param handle is the data structure, where the mounted directories are saved.
     693             :  * @param where the key, that should be looked up.
     694             :  * @return the mountpoint associated with the key
     695             :  * @ingroup mount
     696             :  */
     697       26178 : Key * mountGetMountpoint (KDB * handle, const Key * where)
     698             : {
     699             :         Backend * backend_handle;
     700             : 
     701       26190 :         backend_handle = mountGetBackend (handle, where);
     702       26190 :         if (!backend_handle)
     703             :         {
     704             :                 return 0;
     705             :         }
     706             : 
     707       26190 :         return backend_handle->mountpoint;
     708             : }
     709             : 
     710             : 
     711             : /**
     712             :  * Lookup a backend handle for a specific key.
     713             :  *
     714             :  * The required canonical name is ensured by using a key as parameter,
     715             :  * which will transform the key to canonical representation.
     716             :  *
     717             :  * Will return handle when no more specific KDB could be
     718             :  * found.
     719             :  *
     720             :  * If key is 0 or invalid the default backend will be returned.
     721             :  *
     722             :  * @param handle is the data structure, where the mounted directories are saved.
     723             :  * @param key the key, that should be looked up.
     724             :  * @return the backend handle associated with the key
     725             :  * @ingroup mount
     726             :  */
     727      495744 : Backend * mountGetBackend (KDB * handle, const Key * key)
     728             : {
     729      495744 :         if (!key || !strcmp (keyName (key), "")) return handle->defaultBackend;
     730             : 
     731      495691 :         Backend * ret = trieLookup (handle->trie, key);
     732      495691 :         if (!ret) return handle->defaultBackend;
     733             :         return ret;
     734             : }

Generated by: LCOV version 1.13