/**@return a backend which gives plugin configuration of the module * which is currently point to. * * @param modules the modules to work with * @param errorKey the key to issue warnings and errors to */ Backend* elektraBackendOpenModules(KeySet *modules, Key *errorKey) { Backend *backend = elektraBackendAllocate(); cursor_t save = ksGetCursor (modules); KeySet *defaultConfig = ksNew(5, keyNew("system/module", KEY_VALUE, "1", KEY_END), keyNew("user/module", KEY_VALUE, "1", KEY_END), KS_END); Key *cur = ksCurrent(modules); Plugin *plugin = elektraPluginOpen(keyBaseName(cur), modules, defaultConfig, errorKey); if (!plugin) { /* Error already set in plugin */ elektraFree(backend); return 0; } Key *mp = keyNew ("system/elektra/modules", KEY_VALUE, "modules", KEY_END); keyAddBaseName (mp, keyBaseName(cur)); backend->getplugins[0] = plugin; plugin->refcounter = 1; backend->mountpoint = mp; keyIncRef(backend->mountpoint); ksSetCursor (modules, save); return backend; }
/** * @brief sets mountpoint * * @param backend where the mountpoint should be set * @param elektraConfig the config where the mountpoint can be found * @param [out] errorKey the name also has the mountpoint set * * @pre ksCurrent() is root key * @post ksCurrent() is root key * * @retval -1 if no mountpoint is found or memory allocation problem * @retval 0 on success */ int elektraBackendSetMountpoint(Backend *backend, KeySet *elektraConfig, Key *errorKey) { Key * root = ksCurrent(elektraConfig); Key * searchMountpoint = keyDup(root); keyAddBaseName(searchMountpoint, "mountpoint"); Key * foundMountpoint = ksLookup(elektraConfig, searchMountpoint, 0); keyDel (searchMountpoint); ksLookup(elektraConfig, root, 0); // reset ksCurrent() if (!foundMountpoint) { ELEKTRA_ADD_WARNINGF(14, errorKey, "Could not find mountpoint within root %s", keyName(root)); return -1; } backend->mountpoint = keyNew("", KEY_VALUE, keyBaseName(root), KEY_END); elektraKeySetName(backend->mountpoint, keyString(foundMountpoint), KEY_CASCADING_NAME | KEY_EMPTY_NAME); keySetName(errorKey, keyName(backend->mountpoint)); if (!backend->mountpoint) { ELEKTRA_ADD_WARNINGF(14, errorKey, "Could not create mountpoint with name %s and value %s", keyString(foundMountpoint), keyBaseName(root)); return -1; } keyIncRef(backend->mountpoint); 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)); } }
/** * Calculate the basename of a key name and put it in @p returned finalizing * the string with NULL. * * Some examples: * - basename of @c system/some/keyname is @c keyname * - basename of @c "user/tmp/some key" is @c "some key" * * @param key the key to extract basename from * @param returned a pre-allocated buffer to store the basename * @param maxSize size of the @p returned buffer * @return number of bytes copied to @p returned * @retval 1 on empty name * @retval -1 on NULL pointers * @retval -1 when maxSize is 0 or larger than SSIZE_MAX * @see keyBaseName(), keyGetBaseNameSize() * @see keyName(), keyGetName(), keySetName() * @ingroup keyname */ ssize_t keyGetBaseName (const Key * key, char * returned, size_t maxSize) { if (!key) return -1; if (!returned) return -1; if (!maxSize) return -1; if (maxSize > SSIZE_MAX) return -1; ssize_t maxSSize = maxSize; if (!key->key) { returned[0] = 0; return 1; } ssize_t baseSize = keyGetBaseNameSize (key); if (maxSSize < baseSize) { return -1; } const char * baseName = keyBaseName (key); if (!baseName) { return -1; } strncpy (returned, baseName, baseSize); return baseSize; }
/** * Calculates number of bytes needed to store basename of @p key. * * Key names that have only root names (e.g. @c "system" or @c "user" * or @c "user:domain" ) does not have basenames, thus the function will * return 1 bytes to store "". * * Basenames are denoted as: * - @c system/some/thing/basename -> @c basename * - @c user:domain/some/thing/base\\/name > @c base\\/name * * @param key the key object to work with * @return size in bytes of @p key's basename including ending NULL * @see keyBaseName(), keyGetBaseName() * @see keyName(), keyGetName(), keySetName() * @ingroup keyname */ ssize_t keyGetBaseNameSize (const Key * key) { const char * baseName = keyBaseName (key); if (!baseName) return -1; return elektraStrLen (baseName); }
/** @retval 0 if ksCurrent does not hold an array entry @retval 1 if the array entry will be used because its the first @retval 2 if a new array entry was created @retval -1 error in snprintf */ static int elektraYajlIncrementArrayEntry (KeySet * ks) { Key * current = ksCurrent (ks); const char * baseName = keyBaseName (current); if (baseName && *baseName == '#') { current = keyNew (keyName (current), KEY_END); if (!strcmp (baseName, "###empty_array")) { // get rid of previous key keyDel (ksLookup (ks, current, KDB_O_POP)); // we have a new array entry keySetBaseName (current, 0); keyAddName (current, "#0"); ksAppendKey (ks, current); return 1; } else { // we are in an array elektraArrayIncName (current); ksAppendKey (ks, current); return 2; } } else { // previous entry indicates this is not an array return 0; } }
static int elektraYajlParseMapKey (void * ctx, const unsigned char * stringVal, yajl_size_type stringLen) { KeySet * ks = (KeySet *)ctx; elektraYajlIncrementArrayEntry (ks); Key * currentKey = keyNew (keyName (ksCurrent (ks)), KEY_END); keySetString (currentKey, 0); unsigned char delim = stringVal[stringLen]; char * stringValue = (char *)stringVal; stringValue[stringLen] = '\0'; #ifdef ELEKTRA_YAJL_VERBOSE printf ("elektraYajlParseMapKey stringValue: %s currentKey: %s\n", stringValue, keyName (currentKey)); #endif if (currentKey && !strcmp (keyBaseName (currentKey), "___empty_map")) { // remove old key keyDel (ksLookup (ks, currentKey, KDB_O_POP)); // now we know the name of the object keySetBaseName (currentKey, stringValue); } else { // we entered a new pair (inside the previous object) keySetBaseName (currentKey, stringValue); } ksAppendKey (ks, currentKey); // restore old character in buffer stringValue[stringLen] = delim; return 1; }
static CondResult evalMultipleConditions (Key * key, const Key * meta, const Key * suffixList, Key * parentKey, KeySet * returned) { int countSucceeded = 0; int countFailed = 0; int countNoexpr = 0; KeySet * condKS = elektraMetaArrayToKS (key, keyName (meta)); Key * c; CondResult result = FALSE; while ((c = ksNext (condKS)) != NULL) { if (!keyCmp (c, meta)) continue; result = evaluateKey (c, suffixList, parentKey, key, returned, CONDITION); if (result == TRUE) ++countSucceeded; else if (result == ERROR) ++countFailed; else if (result == NOEXPR) ++countNoexpr; } ksDel (condKS); if (!strcmp (keyBaseName (meta), "all")) { // all conditions must evaluate to TRUE if (countFailed || countNoexpr) return ERROR; else return TRUE; } else if (!strcmp (keyBaseName (meta), "any")) { // at least one conditional must evaluate to TRUE if (countSucceeded) return TRUE; else return ERROR; } else { // no condition must evaluate to FALSE if (countFailed) return ERROR; else return TRUE; } }
static void setSectionNumber(Key *parentKey, Key *key, KeySet *ks) { if (!strcmp(keyBaseName(key), INTERNAL_ROOT_SECTION)) { Key *tmpKey = keyDup(key); keySetMeta(tmpKey, "ini/section", "0"); keySetMeta(key, "ini/section", "0"); keySetString(tmpKey, 0); ksAppendKey(ks, tmpKey); keyDel(tmpKey); return; } Key *lookupKey = keyDup(key); Key *lastKey = keyDup(lookupKey); while (1) { if (!strcmp(keyName(lookupKey), keyName(parentKey))) { if (keyGetMeta(parentKey, "ini/lastSection")) { long previousSection = atol(keyString(keyGetMeta(parentKey, "ini/lastSection"))); ++previousSection; char buffer[21]; //20 digits (long) + \0 snprintf(buffer, sizeof (buffer), "%ld", previousSection); keySetMeta(parentKey, "ini/lastSection", buffer); keySetMeta(key, "ini/section", buffer); } else { keySetMeta(parentKey, "ini/lastSection", "1"); keySetMeta(parentKey, "ini/section", "0"); keySetMeta(key, "ini/section", "1"); } keySetMeta(lastKey, "ini/section", keyString(keyGetMeta(key, "ini/section"))); ksAppendKey(ks, lastKey); break; } if (keyGetMeta(ksLookup(ks, lookupKey, KDB_O_NONE), "ini/section")) { keySetMeta(key, "ini/section", keyString(keyGetMeta(ksLookup(ks, lookupKey, KDB_O_NONE), "ini/section"))); break; } keySetName(lastKey, keyName(lookupKey)); keyAddName(lookupKey, ".."); } keyDel(lookupKey); keyDel(lastKey); }
static int isValidArrayKey (Key * key) { Key * copy = keyDup (key); do { if (keyBaseName (copy)[0] == '#') { if (elektraArrayValidateName (copy) == -1) { keyDel (copy); return 0; } } } while (keySetBaseName (copy, 0) != -1); keyDel (copy); return 1; }
static void test_readFormat (const char * format, const char * fileContent, int numKeys, const char ** keys, const char ** values) { const char * tmpFile = elektraFilename (); FILE * fh = fopen (tmpFile, "w"); if (fh) { fputs (fileContent, fh); fclose (fh); } Key * parentKey = keyNew ("user/tests/simpleini", KEY_VALUE, tmpFile, KEY_END); KeySet * conf = 0; if (format) { conf = ksNew (1, keyNew ("system/format", KEY_VALUE, format, KEY_END), KS_END); } else { conf = ksNew (0, KS_END); } PLUGIN_OPEN ("simpleini"); KeySet * ks = ksNew (numKeys, KS_END); Key * key = 0; succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); Key * lookup = 0; for (int i = 0; i < numKeys; i++) { lookup = keyNew ("user/tests/simpleini", KEY_END); keyAddBaseName (lookup, keys[i]); printf ("testing key '%s'\n", keyBaseName (lookup)); succeed_if ((key = ksLookup (ks, lookup, 0)) != NULL, "key not found"); succeed_if (strcmp (values[i], keyString (key)) == 0, "value of key did not match"); keyDel (lookup); } keyDel (key); ksDel (ks); keyDel (parentKey); PLUGIN_CLOSE (); }
void elektraMetaArrayAdd (Key * key, const char * metaName, const char * value) { const Key * meta = keyGetMeta (key, metaName); Key * arrayKey; if (!meta) { keySetMeta (key, metaName, "#0"); arrayKey = keyDup (keyGetMeta (key, metaName)); keySetString (arrayKey, 0); keyAddBaseName (arrayKey, "#"); } else { arrayKey = keyDup (meta); keyAddBaseName (arrayKey, keyString (meta)); } elektraArrayIncName (arrayKey); keySetMeta (key, keyName (arrayKey), value); keySetMeta (key, metaName, keyBaseName (arrayKey)); keyDel (arrayKey); }
/** * @brief Increment the name of the key by one * * Alphabetical order will remain * * e.g. user/abc/\#9 will be changed to * user/abc/\#_10 * * For the start: * user/abc/\# * will be changed to * user/abc/\#0 * * @param key which base name will be incremented * * @retval -1 on error (e.g. too large array, not validated array) * @retval 0 on success */ int elektraArrayIncName(Key *key) { const char * baseName = keyBaseName(key); int arrayElement = elektraArrayValidateName(key); if (arrayElement == -1) { return -1; } ++baseName; // jump over # while(*baseName == '_') // jump over all _ { ++baseName; } kdb_long_long_t oldIndex = 0; if (!arrayElement) { // we have a start element oldIndex = -1; } else { if (elektraReadArrayNumber(baseName, &oldIndex) == -1) { return -1; } } kdb_long_long_t newIndex = oldIndex+1; // we increment by one char newName[ELEKTRA_MAX_ARRAY_SIZE]; elektraWriteArrayNumber(newName, newIndex); keySetBaseName(key, newName); return 0; }
static void validateArray (KeySet * ks, Key * arrayKey, Key * specKey) { Key * tmpArrayParent = keyDup (arrayKey); keySetBaseName (tmpArrayParent, 0); Key * arrayParent = ksLookup (ks, tmpArrayParent, KDB_O_NONE); keyDel (tmpArrayParent); if (arrayParent == NULL) return; KeySet * ksCopy = ksDup (ks); KeySet * subKeys = ksCut (ksCopy, arrayParent); Key * cur; long validCount = 0; while ((cur = ksNext (subKeys)) != NULL) { if (!keyIsDirectBelow (arrayParent, cur)) continue; if (keyBaseName (cur)[0] == '#') { if (elektraArrayValidateName (cur) == 1) { ++validCount; keySetMeta (cur, "spec/internal/valid", ""); } else { KeySet * invalidCutKS = ksCut (subKeys, cur); Key * toMark; while ((toMark = ksNext (invalidCutKS)) != NULL) { if (strcmp (keyName (cur), keyName (toMark))) keySetMeta (toMark, "conflict/invalid", ""); elektraMetaArrayAdd (arrayParent, "conflict/invalid/hasmember", keyName (toMark)); } ksDel (invalidCutKS); } } } ksDel (subKeys); ksDel (ksCopy); validateArrayRange (arrayParent, validCount, specKey); }
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; }
/**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; }
static int iniKeyToElektraKey (void *vhandle, const char *section, const char *name, const char *value, unsigned short lineContinuation) { CallbackHandle *handle = (CallbackHandle *)vhandle; Key *appendKey = keyDup (handle->parentKey); keySetMeta(appendKey, "ini/lastSection", 0); if (!section || *section == '\0') { section = INTERNAL_ROOT_SECTION; } appendKey = createUnescapedKey(appendKey, section); short mergeSections = 0; Key *existingKey = NULL; if ((existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE))) { if (keyGetMeta(existingKey, "ini/duplicate")) { mergeSections = 1; } } setSectionNumber(handle->parentKey, appendKey, handle->result); appendKey = createUnescapedKey(appendKey, name); existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE); if (existingKey) { //a key with the same name already exists if (handle->array) { //array support is turned on keySetMeta(appendKey, "ini/section", 0); if (keyGetMeta(existingKey, "ini/array")) { //array already exists, appending new key const char *lastIndex = keyString(keyGetMeta(existingKey, "ini/array")); keyAddBaseName(appendKey, lastIndex); keySetMeta(appendKey, "order/parent", 0); keySetMeta(appendKey, "ini/array", 0); keySetMeta(appendKey, "order", 0); if (elektraArrayIncName(appendKey) == 1) { return -1; } keySetString(appendKey, value); keySetMeta(appendKey, "ini/key", 0); ksAppendKey(handle->result, appendKey); keySetMeta(existingKey, "ini/array", keyBaseName(appendKey)); ksAppendKey(handle->result, existingKey); } else { //creating a new array Key *sectionKey = keyDup(appendKey); keyAddName(sectionKey, ".."); char *origVal = strdup(keyString(existingKey)); keySetString(appendKey, ""); keySetMeta(appendKey, "ini/array", "#1"); keySetMeta(appendKey, "order/parent", keyName(sectionKey)); setSectionNumber(handle->parentKey, appendKey, handle->result); setOrderNumber(handle->parentKey, appendKey); keySetMeta(appendKey, "ini/key", ""); ksAppendKey(handle->result, keyDup(appendKey)); keySetMeta(appendKey, "ini/key", 0); keySetMeta(appendKey, "ini/array", 0); keySetMeta(appendKey, "parent", 0); keyAddName(appendKey, "#"); keySetMeta(appendKey, "order", 0); if (elektraArrayIncName(appendKey) == -1) { free(origVal); return -1; } keySetString(appendKey, origVal); ksAppendKey(handle->result, keyDup(appendKey)); free(origVal); if (elektraArrayIncName(appendKey) == -1) { return -1; } keySetMeta(appendKey, "parent", 0); keySetString(appendKey, value); ksAppendKey(handle->result, keyDup(appendKey)); keyDel(appendKey); keyDel(sectionKey); } return 1; } else if(!lineContinuation) { ELEKTRA_SET_ERRORF(141, handle->parentKey, "Key: %s\n", name); return -1; } } setSectionNumber(handle->parentKey, appendKey, handle->result); if (value == NULL) keySetMeta(appendKey, "ini/empty", ""); if (!lineContinuation) { flushCollectedComment (handle, appendKey); keySetString (appendKey, value); keySetMeta(appendKey, "ini/key", ""); ksAppendKey (handle->result, appendKey); if (mergeSections) { keySetMeta(appendKey, "order", 0); insertNewKeyIntoExistendOrder(appendKey, handle->result); } else { setOrderNumber(handle->parentKey, appendKey); } } else { existingKey = ksLookup (handle->result, appendKey, KDB_O_NONE); keyDel (appendKey); /* something went wrong before because this key should exist */ if (!existingKey) return -1; elektraKeyAppendLine(existingKey, value); } 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; }
static int csvRead(KeySet *returned, Key *parentKey, char delim, short useHeader, unsigned long fixColumnCount, const char **colNames) { const char *fileName; fileName = keyString(parentKey); FILE *fp = NULL; fp = fopen(fileName, "rb"); if(!fp) { ELEKTRA_SET_ERRORF(116, parentKey, "couldn't open file %s\n", fileName); return -1; } unsigned long length = 0; length = getLineLength(fp); if(length == 0) { ELEKTRA_ADD_WARNING(118, parentKey, "Empty file"); fclose(fp); return -2; } char *lineBuffer; lineBuffer = elektraMalloc((length * sizeof(char))+1); if(!lineBuffer) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); return -1; } if(!fgets(lineBuffer, length, fp)) { ELEKTRA_SET_ERROR(116, parentKey, "Cant read from file"); return -1; } unsigned long columns = 0; columns = getColumnCount(lineBuffer, delim); if(fixColumnCount) { if(columns != fixColumnCount) { ELEKTRA_SET_ERROR(117, parentKey, "illegal number of columns in Header line"); elektraFree(lineBuffer); fclose(fp); return -1; } } unsigned long colCounter = 0; unsigned long lineCounter = 0; unsigned long offset = 0; char *col; char buf[INTSTR_MAX]; int nr_keys = 1; KeySet *header = ksNew(0, KS_END); Key *key; if(useHeader == 1) { colCounter = 0; offset = 0; while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL) { offset += elektraStrLen(col); key = keyDup(parentKey); if(colNames && (colNames+colCounter)) { keyAddBaseName(key, colNames[colCounter]); } else { keyAddBaseName(key, col); } keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); ksAppendKey(header, key); ++colCounter; } fseek(fp, 0, SEEK_SET); } else { colCounter = 0; //if no headerline exists name the columns 0..N where N is the number of columns key = keyDup(parentKey); keyAddName(key, "#"); while(colCounter < columns) { if(elektraArrayIncName(key) == -1) { elektraFree(lineBuffer); keyDel(key); ksDel(header); fclose(fp); return -1; } keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); if(colNames && (colNames+colCounter)) keySetBaseName(key, colNames[colCounter]); ksAppendKey(header, keyDup(key)); ++colCounter; } keyDel(key); if(useHeader == 0) fseek(fp, 0, SEEK_SET); } Key *dirKey; Key *cur; dirKey = keyDup(parentKey); keyAddName(dirKey, "#"); while(!feof(fp)) { length = getLineLength(fp); if(length == 0) break; if(elektraRealloc((void **)&lineBuffer, (length * sizeof(char))+1) < 0) { fclose(fp); elektraFree(lineBuffer); ksDel(header); keyDel(dirKey); ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); return -1; } fgets(lineBuffer, length, fp); if(elektraArrayIncName(dirKey) == -1) { elektraFree(lineBuffer); keyDel(dirKey); ksDel(header); fclose(fp); return -1; } ++nr_keys; offset = 0; colCounter = 0; char *lastIndex = "#0"; while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL) { cur = getKeyByOrderNr(header, colCounter); offset += elektraStrLen(col); key = keyDup(dirKey); keyAddBaseName(key, keyBaseName(cur)); keySetString(key, col); keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); ksAppendKey(returned, key); lastIndex = (char *)keyBaseName(key); ++nr_keys; ++colCounter; } keySetString(dirKey, lastIndex); ksAppendKey(returned, keyDup(dirKey)); if(colCounter != columns) { if(fixColumnCount) { ELEKTRA_SET_ERRORF(117, parentKey, "illegal number of columns in line %lu", lineCounter); elektraFree(lineBuffer); fclose(fp); keyDel(dirKey); ksDel(header); return -1; } ELEKTRA_ADD_WARNINGF(118, parentKey, "illegal number of columns in line %lu", lineCounter); } ++lineCounter; } key = keyDup(parentKey); keySetString(key, keyBaseName(dirKey)); ksAppendKey(returned, key); keyDel(dirKey); fclose(fp); elektraFree(lineBuffer); ksDel(header); return 1; }
/** * @retval 1 and an allocated string of the pluginName if a new plugins should be created. * @retval 2 and an allocated string of the referenceName if an old plugin should be used * @retval 3 and both if a new plugin should be created and made available for later * back referencing. * @retval -1 on error */ int elektraProcessPlugin (Key * cur, int * pluginNumber, char ** pluginName, char ** referenceName, Key * errorKey) { const char * fullname = keyBaseName (cur); size_t fullsize = keyGetBaseNameSize (cur); if (fullname[0] != '#') { ELEKTRA_ADD_WARNING (18, errorKey, fullname); return -1; } if (fullname[1] < '0' || fullname[1] > '9') { ELEKTRA_ADD_WARNING (19, errorKey, fullname); return -1; } *pluginNumber = fullname[1] - '0'; if (*pluginNumber > NR_OF_PLUGINS) { ELEKTRA_ADD_WARNING (20, errorKey, fullname); return -1; } if (fullname[2] == '#') { char prefixReferenceName[] = "system/elektra/plugins/"; /* We have a back reference here */ if (fullname[fullsize - 2] == '#') { const char * iter = &fullname[3]; size_t pluginNameSize = 1; /* For null character */ size_t referenceNameSize = 0; /* We will introduce a new plugin */ while (*iter != '#') { ++iter; ++pluginNameSize; } *pluginName = elektraMalloc (pluginNameSize); strncpy (*pluginName, &fullname[3], pluginNameSize); (*pluginName)[pluginNameSize - 1] = 0; referenceNameSize = fullsize - pluginNameSize - 4; ++iter; /* advance to one after hash */ *referenceName = elektraMalloc (referenceNameSize + sizeof (prefixReferenceName)); strncpy (*referenceName, prefixReferenceName, sizeof (prefixReferenceName)); strncat (*referenceName, iter, referenceNameSize); (*referenceName)[referenceNameSize + sizeof (prefixReferenceName) - 2] = 0; return 3; } else { /* We reference back to a plugin */ *referenceName = elektraMalloc (fullsize - 3 + sizeof (prefixReferenceName) - 1); strncpy (*referenceName, prefixReferenceName, sizeof (prefixReferenceName)); strncat (*referenceName, &fullname[3], fullsize - 3); return 2; } } else { *pluginName = elektraMalloc (fullsize - 2); /* don't alloc for #n */ strncpy (*pluginName, &fullname[2], fullsize - 2); return 1; } /* Should not be reached */ return 0; }
int elektraSortTopology (KeySet * ks, Key ** array) { if (ks == NULL || array == NULL) return -1; KeySet * done = ksNew (0, KS_END); ksRewind (ks); Key * cur; ssize_t size = ksGetSize (ks); Key * orderCounter = keyNew ("/#", KEY_CASCADING_NAME, KEY_END); elektraArrayIncName (orderCounter); _adjMatrix adjMatrix[size]; int i = 0; int retVal = 1; int depCount = 0; Key ** localArray = elektraMalloc (size * sizeof (Key *)); elektraKsToMemArray (ks, localArray); qsort (localArray, size, sizeof (Key *), topCmpOrder); for (long j = 0; j < size; ++j) { adjMatrix[j].key = localArray[j]; adjMatrix[j].isResolved = 0; adjMatrix[j].deps = elektraCalloc (sizeof (unsigned long) * size); } kdb_octet_t hasOrder = 0; if (keyGetMeta (localArray[0], "order")) hasOrder = 1; unsigned int unresolved = 0; for (int j = 0; j < size; ++j) { cur = localArray[j]; KeySet * deps = elektraMetaArrayToKS (cur, "dep"); keyDel (ksLookupByName (deps, "dep", KDB_O_POP)); Key * tmpDep; switch (ksGetSize (deps)) { case -1: { // key has no dependencies, give it an order number and add it to list of resolved dependencies keySetMeta (cur, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (cur)); adjMatrix[j].isResolved = 1; ksDel (deps); break; } case 1: { // only 1 dependency: // test if it's reflexive tmpDep = ksHead (deps); if (!strcmp (keyName (cur), keyString (tmpDep))) { keySetMeta (cur, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (cur)); adjMatrix[j].isResolved = 1; ksDel (deps); break; } // if not, fallthrough to normal dependency handling } default: { int gotUnresolved = 0; while ((tmpDep = ksNext (deps)) != NULL) { if (!isValidKeyName (keyString (tmpDep))) { // invalid keyname -> ERROR retVal = -1; break; } i = getArrayIndex (tmpDep, adjMatrix, size); if (i == -1) { // key doesn't exist yet but has valid name, ignore it. continue; } else if (i == j) { // reflexiv depencency, do nothing } else { if (!adjMatrix[i].isResolved) { // unresolved dependency adjMatrix[j].deps[i] = 1; ++gotUnresolved; // simple cycle detection if (adjMatrix[i].deps[j]) { retVal = 0; break; } } } } if (gotUnresolved) { adjMatrix[j].isResolved = 0; ++unresolved; // cound unresolved dependencies depCount += gotUnresolved; } ksDel (deps); break; } } if (retVal <= 0) break; } if (retVal <= 0) { // error or cycle: goto cleanup goto TopSortCleanup; } // resolve all dependencies that can be resolved immediately for (int j = 0; j < size; ++j) { if (adjMatrix[j].isResolved) depCount -= resolveDep (j, adjMatrix, size); } ssize_t resolved = ksGetSize (done); if (((depCount + resolved) >= size) && (unresolved)) { // more dependencies dependencies than keys: // cycle found ! retVal = 0; goto TopSortCleanup; } if (unresolved) { int found = 1; // we have unresolved dependencies for (int j = 0; j < size + 1; ++j) { // loop until no dependency can be resolved anymore if (j == size) { if (found) { found = 0; j = -1; unresolved = 0; continue; } else break; } if (adjMatrix[j].isResolved) continue; ++unresolved; if (hasOrder) { // resolve by order int ret = resolveDeps (j, adjMatrix, size, done, orderCounter); if (ret == -1) break; j = -1; found = 1; continue; } else { // resolve next possible dependency in keyset if (!hasUnresolvedDependencies (j, adjMatrix, size)) { adjMatrix[j].isResolved = 1; resolveDep (j, adjMatrix, size); keySetMeta (localArray[j], "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (localArray[j])); found = 1; } } } } if (unresolved == 0) { // everything resolved // add dependencies in topological order to array elektraKsToMemArray (ks, array); qsort (array, size, sizeof (Key *), topCmpOrder); retVal = 1; } else { // still unresolved dependencies left: // there must be a cycle somewhere retVal = 0; } TopSortCleanup: ksDel (done); keyDel (orderCounter); elektraFree (localArray); for (ssize_t j = 0; j < size; ++j) { elektraFree (adjMatrix[j].deps); } return retVal; }
/** * @internal * * elektraSortTopology helper * resolve all dependencies of the key with the index j in our matrix. */ static int resolveDeps (unsigned int j, _adjMatrix * adjMatrix, size_t size, KeySet * done, Key * orderCounter) { unsigned int loops = 0; unsigned int frontier[size]; unsigned int todo = 0; for (unsigned int i = 0; i < size; ++i) { if (adjMatrix[j].deps[i]) { frontier[i] = 1; ++todo; } else { frontier[i] = 0; } } int found = 1; // loop until all dependencies are added to frontier while (found) { found = 0; for (unsigned int i = 0; i < size; ++i) { if (!frontier[i]) continue; if (hasUnresolvedDependencies (i, adjMatrix, size)) { for (unsigned int k = 0; k < size; ++k) { if (adjMatrix[i].deps[k]) { if (!frontier[k]) { found = 1; ++todo; frontier[k] = 1; } } } } } } if (todo == 0) { // all dependencies are already resolved, give key an order number and add it to // the our list of resolved keys (done) adjMatrix[j].isResolved = 1; resolveDep (j, adjMatrix, size); keySetMeta (adjMatrix[j].key, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (adjMatrix[j].key)); return 1; } unsigned int max_loops = todo; for (unsigned int i = 0; todo; ++i) { if (i == size) { ++loops; i = 0; } if (loops > max_loops) return -1; // more loops than we had unresolved keys -> cycle if (!frontier[i]) continue; if (!hasUnresolvedDependencies (i, adjMatrix, size)) { resolveDep (i, adjMatrix, size); frontier[i] = 0; --todo; adjMatrix[i].isResolved = 1; resolveDep (i, adjMatrix, size); keySetMeta (adjMatrix[i].key, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (adjMatrix[i].key)); } } return 1; }