static int csvWrite(KeySet *returned, Key *parentKey, char delim, short useHeader) { FILE *fp; fp = fopen(keyString(parentKey), "w"); if(!fp) { ELEKTRA_SET_ERROR_SET(parentKey); return -1; } keyDel(ksLookup(returned, parentKey, KDB_O_POP)); unsigned long colCounter = 0; unsigned long columns = 0; unsigned long lineCounter = 0; Key *cur; KeySet *toWriteKS; Key *toWrite; while((cur = ksNext(returned)) != NULL) { if(keyRel(parentKey, cur) != 1) continue; if(useHeader) { useHeader = 0; continue; } toWriteKS = ksCut(returned, cur); colCounter = 0; while(1) { toWrite = getKeyByOrderNr(toWriteKS, colCounter); if(!toWrite) break; if(colCounter) fprintf(fp, "%c", delim); ++colCounter; fprintf(fp, "%s", keyString(toWrite)); } ksDel(toWriteKS); fprintf(fp, "\n"); if(columns == 0) { columns = colCounter; } if(colCounter != columns) { ELEKTRA_SET_ERRORF(117, parentKey, "illegal number of columns in line %lu\n", lineCounter); fclose(fp); return -1; } ++lineCounter; } fclose(fp); return 1; }
/** * @retval 1 if one of the backends in split has all * keys below parentKey * @retval 0 if parentKey == 0 or there are keys below * or same than parentKey which do not fit * in any of split keysets * @param split the split object to work with * @param parentKey the key which relation is searched for * @ingroup split */ int elektraSplitSearchRoot (Split * split, Key * parentKey) { if (!parentKey) return 0; for (size_t i = 0; i < split->size; ++i) { if (keyRel (split->parents[i], parentKey) >= 0) return 1; } return 0; }
static void writeHostsEntry(Key* key, KeySet* returned, FILE* fp) { fprintf (fp, "%s\t%s", (char*) keyValue (key), (char*) keyBaseName (key)); /* position the cursor at the current key and * iterate over its subkeys */ ksLookup (returned, key, KDB_O_NONE); Key* alias; while ((alias = ksNext (returned)) != 0) { if (keyRel (key, alias) < 1) break; fprintf (fp, " %s", (char*) keyBaseName (alias)); } }
/**Builds a backend out of the configuration supplied * from: * @verbatim system/elektra/mountpoints/<name> @endverbatim * * The root key must be like the above example. You do * not need to rewind the keyset. But every key must be * below the root key. * * The internal consistency will be checked in this * function. If necessary parts are missing, like * no plugins, they cant be loaded or similar 0 * will be returned. * * ksCut() is perfectly suitable for cutting out the * configuration like needed. * * @note The given KeySet will be deleted within the function, * don't use it afterwards. * * @param elektraConfig the configuration to work with. * It is used to build up this backend. * @param modules used to load new modules or get references * to existing one * @return a pointer to a freshly allocated backend * this could be the requested backend or a so called * "missing backend". * @retval 0 if out of memory * @ingroup backend */ Backend* elektraBackendOpen(KeySet *elektraConfig, KeySet *modules, Key *errorKey) { Key * cur; Key * root; KeySet *referencePlugins = 0; KeySet *systemConfig = 0; int failure = 0; referencePlugins = ksNew(0, KS_END); ksRewind(elektraConfig); root = ksNext (elektraConfig); Backend *backend = elektraBackendAllocate(); while ((cur = ksNext(elektraConfig)) != 0) { if (keyRel (root, cur) == 1) { // direct below root key KeySet *cut = ksCut (elektraConfig, cur); if (!strcmp(keyBaseName(cur), "config")) { systemConfig = elektraRenameKeys(cut, "system"); ksDel (cut); } else if (!strcmp(keyBaseName(cur), "getplugins")) { if (elektraProcessPlugins(backend->getplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(13, errorKey, "elektraProcessPlugins for get failed"); failure = 1; } } else if (!strcmp(keyBaseName(cur), "mountpoint")) { backend->mountpoint = keyNew("", KEY_VALUE, keyBaseName(root), KEY_END); elektraKeySetName(backend->mountpoint, keyString(cur), KEY_CASCADING_NAME | KEY_EMPTY_NAME); if (!backend->mountpoint) { if (!failure) ELEKTRA_ADD_WARNINGF(14, errorKey, "Could not create mountpoint with name %s and value %s", keyString(cur), keyBaseName(root)); failure = 1; } keyIncRef(backend->mountpoint); ksDel (cut); } else if (!strcmp(keyBaseName(cur), "setplugins")) { if (elektraProcessPlugins(backend->setplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for set failed"); failure = 1; } } else if (!strcmp(keyBaseName(cur), "errorplugins")) { if (elektraProcessPlugins(backend->errorplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for error failed"); failure = 1; } } else { // no one cares about that config if (!failure) ELEKTRA_ADD_WARNING(16, errorKey, keyBaseName(cur)); ksDel (cut); } } } if (failure) { Backend *tmpBackend = elektraBackendOpenMissing(backend->mountpoint); elektraBackendClose(backend, errorKey); backend = tmpBackend; } ksDel (systemConfig); ksDel (elektraConfig); ksDel (referencePlugins); return backend; }
/** * Walks through kdb->split and adds all backends below parentKey to split. * * Sets syncbits to 2 if it is a default or root backend (which needs splitting). * The information is copied from kdb->split. * * @pre split needs to be empty, directly after creation with elektraSplitNew(). * * @pre there needs to be a valid defaultBackend * but its ok not to have a trie inside KDB. * * @pre parentKey must be a valid key! (could be implemented more generally, * but that would require splitting up of keysets of the same backend) * * @param split will get all backends appended * @param kdb the handle to get information about backends * @param parentKey the information below which key the backends are from interest * @ingroup split * @retval 1 always */ int elektraSplitBuildup (Split * split, KDB * kdb, Key * parentKey) { /* For compatibility reasons invalid names are accepted, too. * This solution is faster than checking the name of parentKey * every time in loop. * The parentKey might be null in some unit tests, so also check * for this. */ const char * name = keyName (parentKey); if (!parentKey || !name || !strcmp (name, "") || !strcmp (name, "/")) { parentKey = 0; } else if (name[0] == '/') { Key * key = keyNew (0, KEY_END); for (elektraNamespace ins = KEY_NS_FIRST; ins <= KEY_NS_LAST; ++ins) { if (!elektraKeySetNameByNamespace (key, ins)) continue; keyAddName (key, keyName (parentKey)); elektraSplitBuildup (split, kdb, key); } keyDel (key); return 1; } /* Returns the backend the key is in or the default backend otherwise */ Backend * backend = elektraMountGetBackend (kdb, parentKey); #if DEBUG && VERBOSE printf (" with parent %s\n", keyName (parentKey)); #endif for (size_t i = 0; i < kdb->split->size; ++i) { #if DEBUG && VERBOSE printf (" %zu with parent %s\n", i, keyName (kdb->split->parents[i])); #endif if (!parentKey) { #if DEBUG && VERBOSE printf (" def add %s\n", keyName (kdb->split->parents[i])); #endif /* Catch all: add all mountpoints */ elektraSplitAppend (split, kdb->split->handles[i], keyDup (kdb->split->parents[i]), kdb->split->syncbits[i]); } else if (backend == kdb->split->handles[i] && keyRel (kdb->split->parents[i], parentKey) >= 0) { #if DEBUG && VERBOSE printf (" exa add %s\n", keyName (kdb->split->parents[i])); #endif /* parentKey is exactly in this backend, so add it! */ elektraSplitAppend (split, kdb->split->handles[i], keyDup (kdb->split->parents[i]), kdb->split->syncbits[i]); } else if (keyRel (parentKey, kdb->split->parents[i]) >= 0) { #if DEBUG && VERBOSE printf (" rel add %s\n", keyName (kdb->split->parents[i])); #endif /* this backend is completely below the parentKey, so lets add it. */ elektraSplitAppend (split, kdb->split->handles[i], keyDup (kdb->split->parents[i]), kdb->split->syncbits[i]); } } return 1; }
/**Builds a backend out of the configuration supplied * from: * @verbatim system/elektra/mountpoints/<name> @endverbatim * * The root key must be like the above example. You do * not need to rewind the keyset. But every key must be * below the root key. * * The internal consistency will be checked in this * function. If necessary parts are missing, like * no plugins, they cant be loaded or similar 0 * will be returned. * * ksCut() is perfectly suitable for cutting out the * configuration like needed. * * @note The given KeySet will be deleted within the function, * don't use it afterwards. * * @param elektraConfig the configuration to work with. * It is used to build up this backend. * @param modules used to load new modules or get references * to existing one * @param errorKey the key where an error and warnings are added * * @return a pointer to a freshly allocated backend * this could be the requested backend or a so called * "missing backend". * @retval 0 if out of memory * @ingroup backend */ Backend* elektraBackendOpen(KeySet *elektraConfig, KeySet *modules, Key *errorKey) { Key * cur; KeySet *referencePlugins = 0; KeySet *systemConfig = 0; int failure = 0; referencePlugins = ksNew(0, KS_END); ksRewind(elektraConfig); Key * root = ksNext (elektraConfig); Backend *backend = elektraBackendAllocate(); if (elektraBackendSetMountpoint(backend, elektraConfig, errorKey) == -1) { // warning already set failure = 1; } while ((cur = ksNext(elektraConfig)) != 0) { if (keyRel (root, cur) == 1) { // direct below root key KeySet *cut = ksCut (elektraConfig, cur); if (!strcmp(keyBaseName(cur), "config")) { systemConfig = elektraRenameKeys(cut, "system"); ksDel (cut); } else if (!strcmp(keyBaseName(cur), "errorplugins")) { if (elektraProcessPlugins(backend->errorplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for error failed"); failure = 1; } } else if (!strcmp(keyBaseName(cur), "getplugins")) { if (elektraProcessPlugins(backend->getplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(13, errorKey, "elektraProcessPlugins for get failed"); failure = 1; } } else if (!strcmp(keyBaseName(cur), "mountpoint")) { ksDel (cut); // already handled by elektraBackendSetMountpoint continue; } else if (!strcmp(keyBaseName(cur), "setplugins")) { if (elektraProcessPlugins(backend->setplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for set failed"); failure = 1; } } else { // no one cares about that config if (!failure) ELEKTRA_ADD_WARNING(16, errorKey, keyBaseName(cur)); ksDel (cut); } } } if (failure) { Backend *tmpBackend = elektraBackendOpenMissing(backend->mountpoint); elektraBackendClose(backend, errorKey); backend = tmpBackend; } ksDel (systemConfig); ksDel (elektraConfig); ksDel (referencePlugins); return backend; }
/** * Load a plugin. * * The array of plugins must be set to 0. * Its length is NR_OF_PLUGINS. * * systemConfig will only be used, not deleted. * * @param config the config with the information how the * plugins should be put together * @param systemConfig the shared (system) config for the plugins. * Every plugin additional get this config. * * @retval -1 on failure */ int elektraProcessPlugins (Plugin ** plugins, KeySet * modules, KeySet * referencePlugins, KeySet * config, KeySet * systemConfig, Key * errorKey) { Key * root; Key * cur; ksRewind (config); root = ksNext (config); while ((cur = ksNext (config)) != 0) { if (keyRel (root, cur) == 1) { char * pluginName = 0; char * referenceName = 0; int pluginNumber = 0; Key * key; if (elektraProcessPlugin (cur, &pluginNumber, &pluginName, &referenceName, errorKey) == -1) { elektraFree (pluginName); elektraFree (referenceName); ksDel (config); return -1; } if (pluginName) { key = keyDup (cur); keyAddBaseName (key, "config"); KeySet * cutConfig = ksCut (config, key); keyDel (key); KeySet * pluginConfig = elektraRenameKeys (cutConfig, "user"); ksDel (cutConfig); if (!pluginConfig) return -1; ksAppend (pluginConfig, systemConfig); ksRewind (pluginConfig); /* TODO: bug ksAppend invalidates cursor */ /* case 1, we create a new plugin, note that errorKey is not passed here, because it would set error information but we only want a warning instead. */ plugins[pluginNumber] = elektraPluginOpen (pluginName, modules, pluginConfig, errorKey); if (!plugins[pluginNumber]) { ELEKTRA_ADD_WARNING (64, errorKey, pluginName); /* Loading plugin did not work */ elektraFree (pluginName); elektraFree (referenceName); ksDel (config); return -1; } /* case 2, we label it for later use */ if (referenceName) ksAppendKey (referencePlugins, keyNew (referenceName, KEY_BINARY, KEY_SIZE, sizeof (plugins[pluginNumber]), KEY_VALUE, &plugins[pluginNumber], KEY_END)); } else { /* case 3, we use an existing plugin */ Key * lookup = ksLookup (referencePlugins, keyNew (referenceName, KEY_END), KDB_O_DEL); if (!lookup) { ELEKTRA_ADD_WARNING (65, errorKey, referenceName); /* Getting a reference plugin at a previous stage did not work. Note that this check is necessary, because loading the plugin could fail for example at errorplugins and at a later point, for example at setplugins it is tried to refer to that.*/ elektraFree (referenceName); ksDel (config); return -1; } plugins[pluginNumber] = *(Plugin **)keyValue (lookup); ++plugins[pluginNumber]->refcounter; } elektraFree (pluginName); elektraFree (referenceName); } else { ELEKTRA_ADD_WARNING (21, errorKey, keyString (cur)); } } ksDel (config); return 0; }
static int listParseConfiguration (Placements * placements, KeySet * config) { Key * cur; Key * key = ksLookupByName (config, "/plugins", 0); KeySet * cutKS = ksCut (config, key); ksRewind (cutKS); if (ksGetSize (cutKS) < 2) return 0; int rc = 0; while ((cur = ksNext (cutKS)) != NULL) { if (keyRel (key, cur) != 1) { continue; } if (keyBaseName (cur)[0] == '#') { if (strcmp (lastIndex, keyBaseName (cur)) < 0) { snprintf (lastIndex, ELEKTRA_MAX_ARRAY_SIZE, "%s", keyBaseName (cur)); } } Key * sub; Key * lookup = keyDup (cur); keyAddBaseName (lookup, "placements"); keyAddBaseName (lookup, "set"); sub = ksLookup (cutKS, lookup, 0); if (sub) { const char * setString = keyString (sub); const char * setStrings[] = { "presetstorage", "presetcleanup", "precommit", "postcommit" }; SetPlacements setPlacement = preSetStorage; while (setPlacement != setEnd) { if (strstr (setString, setStrings[setPlacement])) { rc = 1; ksAppendKey (placements->setKS[setPlacement], keyDup (cur)); } ++setPlacement; } } keySetBaseName (lookup, "get"); sub = ksLookup (cutKS, lookup, 0); if (sub) { const char * getString = keyString (sub); const char * getStrings[] = { "pregetstorage", "postgetstorage", "postgetcleanup" }; GetPlacements getPlacement = preGetStorage; while (getPlacement != getEnd) { if (strstr (getString, getStrings[getPlacement])) { rc = 1; ksAppendKey (placements->getKS[getPlacement], keyDup (cur)); } ++getPlacement; } } keySetBaseName (lookup, "error"); sub = ksLookup (cutKS, lookup, 0); if (sub) { const char * errString = keyString (sub); const char * errStrings[] = { "prerollback", "postrollback" }; ErrPlacements errPlacement = preRollback; while (errPlacement != errEnd) { if (strstr (errString, errStrings[errPlacement])) { rc = 1; ksAppendKey (placements->errKS[errPlacement], keyDup (cur)); } ++errPlacement; } } keyDel (lookup); } ksDel (cutKS); return rc; }