static void test_defaultonly() { printf ("Test mounting with default only\n"); KDB *kdb = kdb_new(); Key *errorKey = keyNew(0); KeySet *modules = modules_config(); succeed_if (elektraMountOpen(kdb, minimal_config(), modules, errorKey) == 0, "could not buildup mount"); succeed_if (elektraMountDefault(kdb, modules, errorKey) == 0, "could not mount default backend"); // output_split (kdb->split); succeed_if (kdb->split->size == 4, "size of split not correct"); Key *mp = keyNew("spec", KEY_VALUE, "default", KEY_END); compare_key(mp, kdb->split->parents[0]); keySetName(mp, "dir"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[1]); keySetName(mp, "user"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[2]); keySetName(mp, "system"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[3]); succeed_if(output_warnings (errorKey), "warnings found"); succeed_if(output_error (errorKey), "error found"); succeed_if (!kdb->trie, "trie should be empty"); Key *searchKey = keyNew("", KEY_END); Backend *b2 = 0; keySetName (searchKey, "user"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2 == 0, "should be default backend"); keySetName(searchKey, "user/tests/simple"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2 == 0, "should be default backend"); keySetName(searchKey, "user/tests/simple/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2 == 0, "should be default backend"); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2 == 0, "should be default backend"); keyDel (mp); keyDel (searchKey); kdb_del (kdb); keyDel (errorKey); ksDel (modules); }
/** After writing the key this function rereads the key and print it*/ void check_key() { Key * error_key = keyNew(KEY_END); KDB * kdb_handle = kdbOpen(error_key); Key * top = keyNew(KEY_END); keySetName(top, "user/sw/MyApp"); // == 14 KeySet * ks = ksNew(0); kdbGet(kdb_handle, ks, top); Key * key = keyNew(KEY_END); keySetName(key, "user/sw/MyApp/Tests/TestKey1"); // == 14 Key * result = ksLookup(ks, key, KDB_O_NONE); const char * key_name = keyName(result); const char * key_value = keyString(result); const char * key_comment = keyString(keyGetMeta(result, "comment")); printf("key: %s value: %s comment: %s", key_name, key_value, key_comment); ksDel(ks); keyDel(key); keyDel(top); kdbClose(kdb_handle, error_key); keyDel(error_key); }
static void test_umlauts() { printf ("Test umlauts trie\n"); Trie *trie = test_insert (0, "user/umlauts/test", "slash"); trie = test_insert (trie, "user/umlauts#test", "hash"); trie = test_insert (trie, "user/umlauts test", "space"); trie = test_insert (trie, "user/umlauts\200test", "umlauts"); exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (!backend, "there should be no backend"); Key *mp = keyNew("user/umlauts/test", KEY_VALUE, "slash", KEY_END); keySetName(searchKey, "user/umlauts/test"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/umlauts#test"); keySetName(mp, "user/umlauts#test"); keySetString(mp, "hash"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/umlauts test"); keySetName(mp, "user/umlauts test"); keySetString(mp, "space"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/umlauts\200test"); keySetName(mp, "user/umlauts\200test"); keySetString(mp, "umlauts"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); // output_trie(trie); elektraTrieClose(trie, 0); keyDel (mp); keyDel (searchKey); }
/** * @internal * Create a new key with a different root or common name. * * Does not modify `key`. The new key needs to be freed after usage. * * Preconditions: The key name starts with `source`. * * Example: * ``` * Key * source = keyNew("user/plugins/foo/placements/get", KEY_END); * Key * dest = renameKey ("user/plugins/foo", "user/plugins/bar", source); * succeed_if_same_string (keyName(dest), "user/plugins/bar/placements/get"); * ``` * * * @param source Part of the key name to replace * @param dest Replaces `source` * @param key key * @return key with new name */ static Key * renameKey (const char * source, const char * dest, Key * key) { const char * name = keyName (key); char * baseKeyNames = strndup (name + strlen (source), strlen (name)); Key * moved = keyDup (key); keySetName (moved, dest); keyAddName (moved, baseKeyNames); elektraFree (baseKeyNames); return moved; }
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 void test_simple() { printf ("Test simple trie\n"); Trie *trie = test_insert (0, "user/tests/simple", "simple"); exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (!backend, "there should be no backend"); Key *mp = keyNew("user/tests/simple", KEY_VALUE, "simple", KEY_END); keySetName(searchKey, "user/tests/simple"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/tests/simple/below"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); elektraTrieClose(trie, 0); keyDel (mp); keyDel (searchKey); }
/** * Closes the session with the Key database. * * @pre The handle must be a valid handle as returned from kdbOpen() * * @pre errorKey must be a valid key, e.g. created with keyNew() * * This is the counterpart of kdbOpen(). * * You must call this method when you finished your affairs with the key * database. You can manipulate Key and KeySet objects also after * kdbClose(), but you must not use any kdb*() call afterwards. * * The @p handle parameter will be finalized and all resources associated to it * will be freed. After a kdbClose(), the @p handle cannot be used anymore. * * @param handle contains internal information of * @link kdbOpen() opened @endlink key database * @param errorKey the key which holds error/warning information * @retval 0 on success * @retval -1 on NULL pointer * @ingroup kdb */ int kdbClose (KDB * handle, Key * errorKey) { if (!handle) { return -1; } Key * initialParent = keyDup (errorKey); int errnosave = errno; splitDel (handle->split); trieClose (handle->trie, errorKey); backendClose (handle->defaultBackend, errorKey); handle->defaultBackend = 0; // not set in fallback mode, so lets check: if (handle->initBackend) { backendClose (handle->initBackend, errorKey); handle->initBackend = 0; } for (int i = 0; i < NR_GLOBAL_POSITIONS; ++i) { for (int j = 0; j < NR_GLOBAL_SUBPOSITIONS; ++j) { elektraPluginClose (handle->globalPlugins[i][j], errorKey); } } if (handle->modules) { elektraModulesClose (handle->modules, errorKey); ksDel (handle->modules); } else { ELEKTRA_ADD_WARNING (47, errorKey, "modules were not open"); } elektraFree (handle); keySetName (errorKey, keyName (initialParent)); keySetString (errorKey, keyString (initialParent)); keyDel (initialParent); errno = errnosave; return 0; }
int main(int argc, char**argv) { Key *parentKey = keyNew("", KEY_END); KDB *kdb = kdbOpen(parentKey); KeySet *conf = ksNew(0); // get all config files kdbGetByName(kdb, conf, parentKey, "/test/lift"); kdbGetByName(kdb, conf, parentKey, "/test/material_lift"); kdbGetByName(kdb, conf, parentKey, "/test/heavy_material_lift"); kdbGetByName(kdb, conf, parentKey, "/test/person_lift"); // get by params int retval = ksGetOpt(argc, argv, conf); if (retval & 1) { printf("%s Version 0.1\n", argv[0]); return 0; } else if (retval & 2) { printf("Usage: %s [OPTIONS]\n" "%s\n" "Example that demonstrates elektra gen parameters\n", argv[0], elektraGenHelpText()); return 0; } else if (retval != 0) { printf ("Error in parsing options %d\n", retval); } // write back to user/test/lift what we got by commandline // that means overrides in *_lift are still active, but // fallbacks will be overriden. if (lift(conf)) { printf("Write out config\n"); keySetName(parentKey, "user/test/lift"); kdbSet(kdb, conf, parentKey); } ksDel(conf); kdbClose(kdb, parentKey); keyDel(parentKey); return retval; }
// keyRel2 helper, returns how many levels check is below key, or 0 if check isn't below int keyGetLevelsBelow (const Key * key, const Key * check) { if (!keyIsBelow (key, check)) return 0; if (keyGetNamespace (key) != keyGetNamespace (check)) return 0; Key * toCheck = keyDup (check); int levels = 0; while (strcmp (keyName (key), keyName (toCheck))) { keySetBaseName (toCheck, 0); if (keyName (toCheck)[0] == '\0') keySetName (toCheck, "/"); ++levels; } keyDel (toCheck); return levels; }
/** * @internal * * @brief Check if an update is needed at all * * @retval -1 an error occurred * @retval 0 no update needed * @retval number of plugins which need update */ static int elektraGetCheckUpdateNeeded (Split * split, Key * parentKey) { int updateNeededOccurred = 0; for (size_t i = 0; i < split->size; i++) { int ret = -1; Backend * backend = split->handles[i]; clear_bit (split->syncbits[i], 1); if (backend->getplugins[RESOLVER_PLUGIN] && backend->getplugins[RESOLVER_PLUGIN]->kdbGet) { ksRewind (split->keysets[i]); keySetName (parentKey, keyName (split->parents[i])); keySetString (parentKey, ""); ret = backend->getplugins[RESOLVER_PLUGIN]->kdbGet (backend->getplugins[RESOLVER_PLUGIN], split->keysets[i], parentKey); // store resolved filename keySetString (split->parents[i], keyString (parentKey)); // no keys in that backend backendUpdateSize (backend, split->parents[i], 0); } // TODO: set error in else case! switch (ret) { case 1: // Seems like we need to sync that set_bit (split->syncbits[i], SPLIT_FLAG_SYNC); ++updateNeededOccurred; break; case 0: // Nothing to do here break; default: ELEKTRA_ASSERT (0, "resolver did not return 1 0 -1, but %d", ret); case -1: // Ohh, an error occurred, lets stop the // process. return -1; } } return updateNeededOccurred; }
void test_tempname() { printf ("Resolve Tempname\n"); KeySet *modules = ksNew(0); elektraModulesInit (modules, 0); Plugin *plugin = elektraPluginOpen("resolver", modules, set_pluginconf(), 0); exit_if_fail (plugin, "could not load resolver plugin"); KeySet *test_config = set_pluginconf(); KeySet *config = elektraPluginGetConfig (plugin); succeed_if (config != 0, "there should be a config"); compare_keyset(config, test_config); ksDel (test_config); succeed_if (plugin->kdbOpen != 0, "no open pointer"); succeed_if (plugin->kdbClose != 0, "no open pointer"); succeed_if (plugin->kdbGet != 0, "no open pointer"); succeed_if (plugin->kdbSet != 0, "no open pointer"); succeed_if (plugin->kdbError!= 0, "no open pointer"); succeed_if (!strcmp(plugin->name, "resolver"), "got wrong name"); resolverHandles *h = elektraPluginGetData(plugin); succeed_if (h != 0, "no plugin handle"); Key *parentKey= keyNew("system", KEY_END); plugin->kdbGet(plugin, 0, parentKey); succeed_if (!strncmp(h->system.tempfile, KDB_DB_SYSTEM "/elektra.ecf", sizeof(KDB_DB_SYSTEM)), "resulting filename not correct"); keySetName(parentKey, "user"); plugin->kdbGet(plugin, 0, parentKey); succeed_if (!strncmp(h->user.tempfile, KDB_DB_HOME "/" KDB_DB_USER "/elektra.ecf.tmp", sizeof(KDB_DB_HOME "/" KDB_DB_USER)), "resulting filename not correct"); keyDel (parentKey); elektraPluginClose(plugin, 0); elektraModulesClose(modules, 0); ksDel (modules); }
int main () { key = keyNew (KEY_ROOT, KEY_END); timeInit (); benchmarkCreate (); timePrint ("Created empty keyset"); benchmarkFillup (); timePrint ("New large keyset"); benchmarkOpen (); keySetName (key, KEY_ROOT); timePrint ("Opened key database"); benchmarkInread (); timePrint ("Initialize read"); benchmarkInwrite (); timePrint ("Initialize write"); benchmarkWriteout (); timePrint ("Write key database"); benchmarkRewrite (); timePrint ("Rewrite key database"); benchmarkReadin (); timePrint ("Read in key database"); benchmarkLookupByName (); timePrint ("Lookup key database"); benchmarkReread (); timePrint ("Re read key database"); benchmarkClose (); timePrint ("Closed key database"); ksDel (large); keyDel (key); }
void test_ro() { Key *key; key = keyNew(KEY_END); key->flags |= KEY_FLAG_RO; succeed_if (keySetString(key, "a") == -1, "read only string, not allowed to set"); succeed_if (keySetBinary(key, "a", 2) == -1, "read only string, not allowed to set"); succeed_if (keySetName(key, "user") == -1, "read only string, not allowed to set"); succeed_if (keySetMeta(key, "meta", "value") == -1, "read only string, not allowed to set"); keyDel (key); key = keyNew(KEY_END); succeed_if (keySetMeta(key, "meta", "value") == sizeof("value"), "could not set meta"); // TODO check if RO keyDel (key); }
static Key *createKeyFromPath(Key *parentKey, const char *treePath) { Key *key = keyDup (parentKey); const char *baseName = (treePath + strlen (AUGEAS_TREE_ROOT) + 1); size_t baseSize = keyGetNameSize(key); size_t keyNameSize = strlen (baseName) + baseSize + 1; char *newName = malloc (keyNameSize); if (!newName) return 0; strcpy (newName, keyName (key)); newName[baseSize - 1] = KDB_PATH_SEPARATOR; newName[baseSize] = 0; strcat (newName, baseName); keySetName(key, newName); free (newName); return key; }
int main() { KeySet *myConfig = ksNew(0, KS_END); Key *key = keyNew("system/test/myapp",KEY_END); KDB *handle = kdbOpen(key); kdbGet(handle, myConfig, key); keySetName(key, "user/test/myapp"); kdbGet(handle, myConfig, key); // check for errors in key keyDel(key); /* ksRewind(myConfig); while ((key = ksNext(myConfig))) { printf ("%s\n", keyName(key)); } */ key = ksLookupByName(myConfig,"/test/myapp/key", 0); // check if key is not 0 and work with it... if (key) { printf("%s\n", keyString(key)); } ksDel (myConfig); // delete the in-memory configuration // maybe you want kdbSet() myConfig here kdbClose(handle, 0); // no more affairs with the key database. return 0; }
/** * @internal * @brief Does the rollback * * @param split all information for iteration * @param parentKey to add warnings (also passed to plugins for the same reason) */ static void elektraSetRollback (Split * split, Key * parentKey) { for (size_t p = 0; p < NR_OF_PLUGINS; ++p) { for (size_t i = 0; i < split->size; i++) { int ret = 0; Backend * backend = split->handles[i]; ksRewind (split->keysets[i]); if (backend->errorplugins[p]) { keySetName (parentKey, keyName (split->parents[i])); ret = backend->errorplugins[p]->kdbError (backend->errorplugins[p], split->keysets[i], parentKey); } if (ret == -1) { ELEKTRA_ADD_WARNING (81, parentKey, keyName (backend->mountpoint)); } } } }
/** * @internal * @brief Does the commit * * @param split all information for iteration * @param parentKey to add warnings (also passed to plugins for the same reason) */ static void elektraSetCommit (Split * split, Key * parentKey) { for (size_t p = COMMIT_PLUGIN; p < NR_OF_PLUGINS; ++p) { for (size_t i = 0; i < split->size; i++) { int ret = 0; Backend * backend = split->handles[i]; if (backend->setplugins[p] && backend->setplugins[p]->kdbSet) { if (p != COMMIT_PLUGIN) { keySetString (parentKey, keyString (split->parents[i])); } keySetName (parentKey, keyName (split->parents[i])); #if DEBUG && VERBOSE printf ("elektraSetCommit: %p # %zu with %s - %s\n", backend, p, keyName (parentKey), keyString (parentKey)); #endif ksRewind (split->keysets[i]); ret = backend->setplugins[p]->kdbSet (backend->setplugins[p], split->keysets[i], parentKey); if (p == COMMIT_PLUGIN) { // name of non-temp file keySetString (split->parents[i], keyString (parentKey)); } } if (ret == -1) { ELEKTRA_ADD_WARNING (80, parentKey, keyName (backend->mountpoint)); } } } }
static void test_cascading() { printf ("Test simple mount with cascading\n"); KDB *kdb = kdb_new(); Key *errorKey = keyNew(0); KeySet *modules = modules_config(); succeed_if (elektraMountOpen(kdb, cascading_config(), modules, errorKey) == 0, "could not open trie"); succeed_if (elektraMountDefault(kdb, modules, errorKey) == 0, "could not mount default backend"); succeed_if(output_warnings (errorKey), "warnings found"); succeed_if(output_error (errorKey), "error found"); exit_if_fail (kdb->trie, "kdb->trie was not build up successfully"); succeed_if (kdb->split->size == 7, "size of split not correct"); Key *mp = keyNew("dir/tests/simple", KEY_VALUE, "simple", KEY_END); compare_key(mp, kdb->split->parents[0]); keySetName(mp, "user/tests/simple"); keySetString (mp, "simple"); compare_key(mp, kdb->split->parents[1]); keySetName(mp, "system/tests/simple"); keySetString (mp, "simple"); compare_key(mp, kdb->split->parents[2]); keyDel (mp); // output_split (kdb->split); // output_trie (kdb->trie); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (!backend, "there should be no backend"); keySetName(searchKey, "system"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (!backend, "there should be no backend"); mp = keyNew("", KEY_VALUE, "simple", KEY_END); elektraKeySetName(mp, "/tests/simple", KEY_CASCADING_NAME); keySetName(searchKey, "user/tests/simple"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/tests/simple/below"); Backend *b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "system/tests/simple"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "system/tests/simple/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "system/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keyDel (errorKey); ksDel (modules); keyDel (mp); keyDel (searchKey); kdb_del (kdb); }
static void test_endings() { printf ("Test endings trie\n"); for (int i=0; i<4; ++i) { Trie *trie = 0; switch (i) { case 0: trie = test_insert (trie, "user/endings/","slash"); trie = test_insert (trie, "user/endings#","hash"); trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings\200","endings"); break; case 1: trie = test_insert (trie, "user/endings#","hash"); trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings\200","endings"); trie = test_insert (trie, "user/endings/","slash"); break; case 2: trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings\200","endings"); trie = test_insert (trie, "user/endings/","slash"); trie = test_insert (trie, "user/endings#","hash"); break; case 3: trie = test_insert (trie, "user/endings\200","endings"); trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings#","hash"); trie = test_insert (trie, "user/endings/","slash"); break; } exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (!backend, "there should be no backend"); Key *mp = keyNew("user/endings", KEY_VALUE, "slash", KEY_END); keySetName(searchKey, "user/endings"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/endings#"); keySetName(mp, "user/endings#"); keySetString(mp, "hash"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings/_"); keySetName(mp, "user/endings"); keySetString(mp, "slash"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be the same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings/X"); keySetName(mp, "user/endings"); keySetString(mp, "slash"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be the same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings_"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (!b2, "there should be no backend"); keySetName(searchKey, "user/endingsX"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (!b2, "there should be no backend"); keySetName(searchKey, "user/endings!"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (!b2, "there should be no backend"); keySetName(searchKey, "user/endings "); keySetName(mp, "user/endings "); keySetString(mp, "space"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings\200"); keySetName(mp, "user/endings\200"); keySetString(mp, "endings"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); // output_trie(trie); elektraTrieClose(trie, 0); keyDel (mp); keyDel (searchKey); } }
static void test_revmoreiterate() { printf ("Test revmoreiterate trie\n"); for (int i=0; i<5; ++i) { Trie *trie = 0; switch (i) { case 0: trie = test_insert (trie, "user/tests", "tests"); trie = test_insert (trie, "user/tests/hosts", "hosts"); trie = test_insert (trie, "user/tests/hosts/below", "below"); trie = test_insert (trie, "system/tests", "systests"); trie = test_insert (trie, "system/tests/hosts", "syshosts"); trie = test_insert (trie, "system/tests/hosts/below", "sysbelow"); trie = test_insert (trie, "system", "system"); trie = test_insert (trie, "user", "user"); break; case 1: trie = test_insert (trie, "system/tests/hosts", "syshosts"); trie = test_insert (trie, "system", "system"); trie = test_insert (trie, "user/tests", "tests"); trie = test_insert (trie, "user/tests/hosts", "hosts"); trie = test_insert (trie, "user/tests/hosts/below", "below"); trie = test_insert (trie, "system/tests", "systests"); trie = test_insert (trie, "user", "user"); trie = test_insert (trie, "system/tests/hosts/below", "sysbelow"); break; case 2: trie = test_insert (trie, "system/tests/hosts/below", "sysbelow"); trie = test_insert (trie, "system/tests/hosts", "syshosts"); trie = test_insert (trie, "user/tests/hosts/below", "below"); trie = test_insert (trie, "user/tests/hosts", "hosts"); trie = test_insert (trie, "user/tests", "tests"); trie = test_insert (trie, "user", "user"); trie = test_insert (trie, "system/tests", "systests"); trie = test_insert (trie, "system", "system"); break; case 3: trie = test_insert (trie, "user/tests/hosts/below", "below"); trie = test_insert (trie, "user/tests/hosts", "hosts"); trie = test_insert (trie, "user/tests", "tests"); trie = test_insert (trie, "user", "user"); trie = test_insert (trie, "system/tests/hosts/below", "sysbelow"); trie = test_insert (trie, "system/tests/hosts", "syshosts"); trie = test_insert (trie, "system/tests", "systests"); trie = test_insert (trie, "system", "system"); break; case 4: trie = test_insert (trie, "system/tests/hosts/below", "sysbelow"); trie = test_insert (trie, "system/tests/hosts", "syshosts"); trie = test_insert (trie, "system/tests", "systests"); trie = test_insert (trie, "system", "system"); trie = test_insert (trie, "user/tests/hosts/below", "below"); trie = test_insert (trie, "user/tests/hosts", "hosts"); trie = test_insert (trie, "user/tests", "tests"); trie = test_insert (trie, "user", "user"); break; } KeySet *mps = set_mountpoints(); exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew(0); keySetName(searchKey, "user"); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, ksLookupByName(mps, "user",0)); // printf ("backend: %p\n", (void*)backend); keySetName(searchKey, "user/tests/hosts/other/below"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, ksLookupByName(mps, "user/tests/hosts",0)); // printf ("b2: %p\n", (void*)b2); keySetName(searchKey, "user/tests/hosts/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, ksLookupByName(mps, "user/tests/hosts",0)); keySetName(searchKey, "user/tests/hosts/below"); Backend *b3 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); compare_key(b3->mountpoint, ksLookupByName(mps, "user/tests/hosts/below",0)); backend = b3; // printf ("b3: %p\n", (void*)b3); keySetName(searchKey, "user/tests/hosts/below/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); compare_key(b3->mountpoint, ksLookupByName(mps, "user/tests/hosts/below",0)); keySetName(searchKey, "system"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, ksLookupByName(mps, "system",0)); // printf ("backend: %p\n", (void*)backend); keySetName(searchKey, "system/tests/hosts/other/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, ksLookupByName(mps, "system/tests/hosts",0)); // printf ("b2: %p\n", (void*)b2); keySetName(searchKey, "system/tests/hosts/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, ksLookupByName(mps, "system/tests/hosts",0)); keySetName(searchKey, "system/tests/hosts/below"); b3 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); compare_key(b3->mountpoint, ksLookupByName(mps, "system/tests/hosts/below",0)); backend = b3; // printf ("b3: %p\n", (void*)b3); keySetName(searchKey, "system/tests/hosts/below/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); compare_key(b3->mountpoint, ksLookupByName(mps, "system/tests/hosts/below",0)); /* printf ("---------\n"); output_trie(trie); */ KeySet *mps_cmp = ksNew(0, KS_END); collect_mountpoints(trie, mps_cmp); succeed_if (ksGetSize(mps_cmp) == 8, "size should be 8"); compare_keyset(mps, mps_cmp); ksDel (mps_cmp); ksDel (mps); elektraTrieClose(trie, 0); keyDel (searchKey); } // end for }
static void test_reviterate() { printf ("Test reviterate trie\n"); Trie * trie = test_insert (0, "user/tests/hosts/below", "below"); trie = test_insert (trie, "user/tests/hosts", "hosts"); exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (!backend, "there should be no backend"); Key *mp = keyNew("user/tests/hosts", KEY_VALUE, "hosts", KEY_END); keySetName(searchKey, "user/tests/hosts"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); // printf ("backend: %p\n", (void*)backend); keySetName(searchKey, "user/tests/hosts/other/below"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); // printf ("b2: %p\n", (void*)b2); keySetName(searchKey, "user/tests/hosts/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); Key *mp2 = keyNew("user/tests/hosts/below", KEY_VALUE, "below", KEY_END); keySetName(searchKey, "user/tests/hosts/below"); Backend *b3 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); succeed_if (backend != b3, "should be different backend"); compare_key(b3->mountpoint, mp2); backend = b3; // printf ("b3: %p\n", (void*)b3); keySetName(searchKey, "user/tests/hosts/below/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); succeed_if (backend == b3, "should be same backend"); compare_key(b3->mountpoint, mp2); KeySet *mps = ksNew(0, KS_END); collect_mountpoints(trie, mps); succeed_if (ksGetSize (mps) == 2, "not both mountpoints collected"); compare_key(ksHead(mps), mp); compare_key(ksTail(mps), mp2); ksDel (mps); elektraTrieClose(trie, 0); keyDel (mp); keyDel (mp2); keyDel (searchKey); }
/** Call a plugin's function in a child process * * This will wrap all the required information to execute the given * command in a keyset and send it over to the child process. Then * it waits for the child process's answer and copies the result * back into the original plugin keyset and plugin key. * * Typically called like * @code int elektraPluginSet (Plugin * handle, KeySet * returned, Key * parentKey) { ElektraPluginProcess * pp = elektraPluginGetData (handle); if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessSend (pp, ELEKTRA_PLUGINPROCESS_SET, returned, parentKey); // actual plugin functionality to be executed in a child process return ELEKTRA_PLUGIN_STATUS_SUCCESS; } * @endcode * * @param pp the data structure containing the plugin's process information * @param command the plugin command that should be executed, e.g. ELEKTRA_PLUGINPROCESS_GET * @param originalKeySet the original key set that the parent process receives * @param key the original key the parent process receives * @retval ELEKTRA_PLUGIN_STATUS_ERROR if the child process communication failed * @retval the called plugin's return value otherwise * @see elektraPluginProcessIsParent for checking if we are in the parent or child process * @ingroup processplugin **/ int elektraPluginProcessSend (const ElektraPluginProcess * pp, pluginprocess_t command, KeySet * originalKeySet, Key * key) { // Ensure we have a keyset when trying to call GET SET and ERROR if ((command == ELEKTRA_PLUGINPROCESS_GET || command == ELEKTRA_PLUGINPROCESS_SET || command == ELEKTRA_PLUGINPROCESS_ERROR) && originalKeySet == NULL) { ELEKTRA_SET_ERROR (191, key, "originalKeySet has to exist when calling GET SET and ERROR via pluginprocess; but it is NULL"); return ELEKTRA_PLUGIN_STATUS_ERROR; } // Construct the command set that controls the pluginprocess communication KeySet * commandKeySet = ksNew (6, KS_END); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/parent/name", KEY_VALUE, keyName (key), KEY_END)); Key * parentKey = keyDup (key); keySetName (parentKey, "/pluginprocess/parent"); ksAppendKey (commandKeySet, parentKey); char * commandStr = longToStr (command); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/command", KEY_VALUE, commandStr, KEY_END)); elektraFree (commandStr); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/version", KEY_VALUE, "1", KEY_END)); // Some plugin functions don't use keysets, in that case don't send any actual payload, signal via flag KeySet * keySet = originalKeySet != NULL ? ksDup (originalKeySet) : NULL; char * payloadSizeStr = longToStr (ksGetSize (originalKeySet)); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/payload/size", KEY_VALUE, originalKeySet == NULL ? "-1" : payloadSizeStr, KEY_END)); elektraFree (payloadSizeStr); // Serialize, currently statically use dump as our default format, this already writes everything out to the pipe ELEKTRA_LOG ("Parent: Sending data to issue command %u it through pipe %s", command, keyString (pp->parentCommandPipeKey)); elektraInvoke2Args (pp->dump, "set", commandKeySet, pp->parentCommandPipeKey); if (keySet != NULL) { ELEKTRA_LOG ("Parent: Sending the payload keyset with %zd keys through the pipe %s", ksGetSize (keySet), keyString (pp->parentPayloadPipeKey)); elektraInvoke2Args (pp->dump, "set", keySet, pp->parentPayloadPipeKey); } // Deserialize ELEKTRA_LOG_DEBUG ("Parent: Waiting for the result now on pipe %s", keyString (pp->childCommandPipeKey)); elektraInvoke2Args (pp->dump, "get", commandKeySet, pp->childCommandPipeKey); if (keySet != NULL) { // clear the keyset before to avoid memleaks caused by dump char * endPtr; int prevErrno = errno; errno = 0; long payloadSize = strtol (keyString (ksLookupByName (commandKeySet, "/pluginprocess/payload/size", KDB_O_NONE)), &endPtr, 10); // in case the payload size fails to be transferred, that it shouldn't, we simply assume the previous size if (*endPtr != '\0' || errno == ERANGE || payloadSize < 0) payloadSize = ksGetSize (keySet); errno = prevErrno; ksDel (keySet); keySet = ksNew (payloadSize, KS_END); elektraInvoke2Args (pp->dump, "get", keySet, pp->childPayloadPipeKey); ELEKTRA_LOG ("Parent: We received %zd keys in return", ksGetSize (keySet)); } // Bring everything back in order by removing our process-related keys Key * parentDeserializedKey = ksLookupByName (commandKeySet, "/pluginprocess/parent", KDB_O_NONE); Key * resultKey = ksLookupByName (commandKeySet, "/pluginprocess/result", KDB_O_NONE); // Parse the result value char * endPtr; int prevErrno = errno; errno = 0; long lresult = strtol (keyString (resultKey), &endPtr, 10); if (*endPtr != '\0' || errno == ERANGE || lresult > INT_MAX || lresult < INT_MIN) { ELEKTRA_SET_ERRORF (191, key, "Received invalid return code or no KeySet: %s", keyString (resultKey)); lresult = ELEKTRA_PLUGIN_STATUS_ERROR; } else // Copy everything back into the actual keysets { Key * parentKeyInOriginalKeySet = keySet != NULL ? ksLookup (originalKeySet, key, KDB_O_NONE) : NULL; // maybe there are just 2 keys with the same name, can happen in theory, so compare memory int parentKeyExistsInOriginalKeySet = parentKeyInOriginalKeySet == key; // if the child added the parent key to the keyset pop it from the keyset // then reinsert key after we copied the data and delete this serialized copy Key * parentKeyInKeySet = keySet != NULL ? ksLookup (keySet, key, KDB_O_POP) : NULL; int childAddedParentKey = parentKeyInKeySet != NULL; // Unfortunately we can't use keyCopy here as ksAppendKey locks it so it will fail // This is the case if the parent key is also contained in the originalKeySet / has been appended // As an invariant we assume plugins don't change the parent key's name during a plugin call // This would interfere with keyset memberships keySetString (key, keyString (parentDeserializedKey)); // Clear metadata before, we allow children to modify it keyRewindMeta (key); const Key * currentMeta; while ((currentMeta = keyNextMeta (key)) != NULL) { keySetMeta (key, keyName (currentMeta), 0); } keyCopyAllMeta (key, parentDeserializedKey); if (childAddedParentKey) keyCopyAllMeta (key, parentKeyInKeySet); if (keySet != NULL) { // in case originalKeySet contains key this would make it stuck // thus remove it here and re-add it afterwards if (parentKeyExistsInOriginalKeySet) ksLookup (originalKeySet, parentKeyInOriginalKeySet, KDB_O_POP); ksCopy (originalKeySet, keySet); if (parentKeyExistsInOriginalKeySet || childAddedParentKey) ksAppendKey (originalKeySet, key); if (childAddedParentKey) keyDel (parentKeyInKeySet); } } errno = prevErrno; // Command finished, cleanup the remaining memory now ksDel (commandKeySet); if (keySet != NULL) ksDel (keySet); return lresult; // Safe, we had a bound check before, and plugins should return values in the int range }
/** Start the child process' command loop * * This will make the child process wait for plugin commands * and execute them, returning the result to the parent. This * is typically called in a plugin's open function. * * @param handle the plugin's handle * @param pp the data structure containing the plugin's process information * @see elektraPluginProcessInit how to use this function in a plugin * @ingroup processplugin **/ void elektraPluginProcessStart (Plugin * handle, ElektraPluginProcess * pp) { int counter = 0; do { KeySet * commandKeySet = ksNew (6, KS_END); KeySet * keySet = NULL; ELEKTRA_LOG_DEBUG ("Child: Wait for commands on pipe %s", keyString (pp->parentCommandPipeKey)); elektraInvoke2Args (pp->dump, "get", commandKeySet, pp->parentCommandPipeKey); if (ksGetSize (commandKeySet) == 0) { ELEKTRA_LOG_DEBUG ("Child: Failed to read from parentCommandPipe, exiting"); ksDel (commandKeySet); break; } Key * payloadSizeKey = ksLookupByName (commandKeySet, "/pluginprocess/payload/size", KDB_O_NONE); char * endPtr; // We'll always write some int value into it, so this should be fine int prevErrno = errno; errno = 0; long payloadSize = strtol (keyString (payloadSizeKey), &endPtr, 10); // in case the payload size fails to be transferred, that it shouldn't, we can only assume no payload if (*endPtr == '\0' && errno != ERANGE && payloadSize >= 0) { keySet = ksNew (payloadSize, KS_END); elektraInvoke2Args (pp->dump, "get", keySet, pp->parentPayloadPipeKey); ELEKTRA_LOG_DEBUG ("Child: We received a KeySet with %zd keys in it", ksGetSize (keySet)); } errno = prevErrno; Key * commandKey = ksLookupByName (commandKeySet, "/pluginprocess/command", KDB_O_NONE); Key * parentNameKey = ksLookupByName (commandKeySet, "/pluginprocess/parent/name", KDB_O_NONE); Key * parentKey = ksLookupByName (commandKeySet, "/pluginprocess/parent", KDB_O_POP); Key * key = keyDup (parentKey); keySetName (key, keyString (parentNameKey)); int result = ELEKTRA_PLUGIN_STATUS_ERROR; // We'll always write some int value into it, so this should be fine prevErrno = errno; errno = 0; long command = strtol (keyString (commandKey), &endPtr, 10); if (*endPtr == '\0' && errno != ERANGE) { ELEKTRA_LOG ("Child: We want to execute the command with the value %ld now", command); // Its hard to figure out the enum size in a portable way but for this comparison it should be ok switch (command) { case ELEKTRA_PLUGINPROCESS_OPEN: counter++; result = handle->kdbOpen (handle, key); break; case ELEKTRA_PLUGINPROCESS_CLOSE: counter--; result = handle->kdbClose (handle, key); break; case ELEKTRA_PLUGINPROCESS_GET: result = handle->kdbGet (handle, keySet, key); break; case ELEKTRA_PLUGINPROCESS_SET: result = handle->kdbSet (handle, keySet, key); break; case ELEKTRA_PLUGINPROCESS_ERROR: result = handle->kdbError (handle, keySet, key); break; default: result = ELEKTRA_PLUGIN_STATUS_ERROR; } ELEKTRA_LOG_DEBUG ("Child: Command executed with return value %d", result); } else { ELEKTRA_LOG_DEBUG ("Child: Unrecognized command %s", keyString (commandKey)); ELEKTRA_SET_ERRORF (191, key, "Received invalid command code or no KeySet: %s", keyString (commandKey)); } errno = prevErrno; char * resultStr = longToStr (result); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/result", KEY_VALUE, resultStr, KEY_END)); elektraFree (resultStr); keySetName (key, "/pluginprocess/parent"); ksAppendKey (commandKeySet, key); keyDel (parentKey); ELEKTRA_LOG_DEBUG ("Child: Writing the results back to the parent"); elektraInvoke2Args (pp->dump, "set", commandKeySet, pp->childCommandPipeKey); if (keySet != NULL) { char * resultPayloadSize = longToStr (ksGetSize (keySet)); keySetString (payloadSizeKey, resultPayloadSize); elektraFree (resultPayloadSize); elektraInvoke2Args (pp->dump, "set", keySet, pp->childPayloadPipeKey); ksDel (keySet); } ksDel (commandKeySet); ELEKTRA_LOG ("Child: Command handled, startup counter is at %d", counter); } while (counter); // Final Cleanup ELEKTRA_LOG_DEBUG ("Child: All done, exiting the child process now"); cleanupPluginData (pp, 0, 1); // All done, exit the child process so it won't do any actual effects in elektra _Exit (EXIT_SUCCESS); }
/* * Processes the current <key> node from reader, converting from XML * to a Key object, and ksAppendKey() it to ks. * * See keyToStream() for an example of a <key> node. * * This function is completelly dependent on libxml. * * @param ks where to put the resulting reded key * @param context a prent key name, so a full name can be calculated * if the XML node for the current key only provides a basename * @param reader where to read from */ static int consumeKeyNode(KeySet *ks, const char *context, xmlTextReaderPtr reader) { xmlChar *nodeName=0; xmlChar *keyNodeName=0; xmlChar *buffer=0; xmlChar *privateContext=0; Key *newKey=0; int appended=0; /* printf("%s", KDB_SCHEMA_PATH); */ keyNodeName=xmlTextReaderName(reader); if (!strcmp((char *)keyNodeName,"key")) { mode_t isdir=0; int isbin=0; int end=0; newKey=keyNew(0); /* a <key> must have one of the following: - a "name" attribute, used as an absolute name overriding the context - a "basename" attribute, that will be appended to the current context - a "parent" plus "basename" attributes, both appended to current context - only a "parent", appended to current context */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"name"); if (buffer) { /* set absolute name */ keySetName(newKey,(char *)buffer); xmlFree(buffer); buffer=0; } else { /* logic for relative name calculation */ privateContext=xmlTextReaderGetAttribute(reader, (const xmlChar *)"parent"); buffer=xmlTextReaderGetAttribute(reader, (const xmlChar *)"basename"); if (context) keySetName(newKey,context); if (privateContext) keyAddName(newKey, (char *)privateContext); if (buffer) keyAddName(newKey,(char *)buffer); xmlFree(privateContext); privateContext=0; xmlFree(buffer); buffer=0; } /* test for a short value attribute, instead of <value> bellow */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"value"); if (buffer) { keySetRaw(newKey,buffer,elektraStrLen((char *)buffer)); xmlFree(buffer); buffer=0; } /* Parse UID */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"uid"); if (buffer) { int errsave = errno; char * endptr; long int uid = strtol ((const char *)buffer, &endptr, 10); errno = errsave; if (endptr != '\0' && *endptr == '\0') { keySetUID(newKey,uid); } xmlFree(buffer); buffer=0; } /* Parse GID */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"gid"); if (buffer) { int errsave = errno; char * endptr; long int gid = strtol ((const char *)buffer, &endptr, 10); errno = errsave; if (endptr != '\0' && *endptr == '\0') { keySetGID(newKey,gid); } xmlFree(buffer); buffer=0; } /* Parse mode permissions */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"mode"); int errsave = errno; if (buffer) keySetMode(newKey,strtol((char *)buffer,0,0)); errno = errsave; xmlFree(buffer); if (xmlTextReaderIsEmptyElement(reader)) { /* we have a <key ..../> element */ if (newKey && !appended) { ksAppendKey(ks,newKey); appended=1; end=1; } } buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"type"); if (buffer) { if (!strcmp((char *)buffer,"binary")) isbin = 1; else if (!strcmp((char *)buffer,"bin")) isbin = 1; } xmlFree(buffer); /* If "isdir" appears, everything different from "0", "false" or "no" marks it as a dir key */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"isdir"); if (!isdir && buffer) { if ( strcmp((char *)buffer,"0") && strcmp((char *)buffer,"false") && strcmp((char *)buffer,"no")) isdir = 1; else isdir = 0; } xmlFree(buffer); if (isdir) keySetDir(newKey); if (isbin) keySetMeta (newKey, "binary", ""); // TODO: should parse arbitrary attributes as metadata /* Parse everything else */ while (!end) { xmlTextReaderRead(reader); nodeName=xmlTextReaderName(reader); if (!strcmp((char *)nodeName,"value")) { if (xmlTextReaderIsEmptyElement(reader) || xmlTextReaderNodeType(reader)==15) { xmlFree (nodeName); continue; } xmlTextReaderRead(reader); buffer=xmlTextReaderValue(reader); if (buffer) { /* Key's value type was already set above */ if (keyIsBinary(newKey)) { /* TODO binary values char *unencoded=0; size_t unencodedSize; unencodedSize=elektraStrLen((char *)buffer)/2; unencoded=elektraMalloc(unencodedSize); unencodedSize=kdbbDecode((char *)buffer,unencoded); if (!unencodedSize) return -1; keySetRaw(newKey,unencoded,unencodedSize); elektraFree (unencoded); */ } else keySetRaw(newKey,buffer,elektraStrLen((char *)buffer)); } xmlFree(buffer); } else if (!strcmp((char *)nodeName,"comment")) { ssize_t commentSize=0; if (xmlTextReaderIsEmptyElement(reader) || xmlTextReaderNodeType(reader)==15) { xmlFree (nodeName); continue; } xmlTextReaderRead(reader); buffer=xmlTextReaderValue(reader); if ((commentSize=keyGetCommentSize(newKey)) > 1) { /*Multiple line comment*/ char *tmpComment=0; tmpComment=elektraMalloc(commentSize+ xmlStrlen(buffer)*sizeof(xmlChar)+1); if (tmpComment) { keyGetComment(newKey,tmpComment,commentSize); strcat(tmpComment,"\n"); strcat(tmpComment,(char *)buffer); keySetComment(newKey,tmpComment); elektraFree (tmpComment); tmpComment=0; } } else keySetComment(newKey,(char *)buffer); xmlFree(buffer); } else if (!strcmp((char *)nodeName,"key")) { /* Here we found </key> or a sub <key>. So include current key in the KeySet. */ if (newKey && !appended) { ksAppendKey(ks,newKey); appended=1; } if (xmlTextReaderNodeType(reader)==15) /* found a </key> */ end=1; else { /* found a sub <key> */ /* prepare the context (parent) */ consumeKeyNode(ks,newKey->key,reader); } } xmlFree (nodeName); } if (privateContext) xmlFree(privateContext); /* seems like we forgot the key, lets delete it */ if (newKey && !appended) { keyDel (newKey); appended=1; } } xmlFree(keyNodeName); return 0; }
int main() { KeySet *ks=ksNew(0); Key *key=0; printf ("Generate some keys..."); ksAppendKey(ks,keyNew("user/sw",KEY_END)); /* a simple key */ ksAppendKey(ks,keyNew(0)); /* an empty key */ ksAppendKey(ks,keyNew("system/sw", KEY_END)); ksAppendKey(ks,keyNew("user/tmp/ex1", KEY_VALUE,"some data", /* with a simple value */ KEY_END)); /* end of args */ ksAppendKey(ks,keyNew("user/tmp/ex2", KEY_VALUE,"some data", /* with a simple value */ KEY_MODE,0777, /* permissions */ KEY_END)); /* end of args */ ksAppendKey(ks,keyNew("user/tmp/ex4", KEY_BINARY, KEY_COMMENT,"value is truncated", KEY_SIZE, 7, KEY_VALUE,"some data", /* value that will be truncated to 7 bytes */ KEY_UID,0, /* root uid */ KEY_END)); /* end of args */ ksAppendKey(ks,keyNew("user/tmp/ex5", KEY_VALUE,"some data", /* value */ KEY_OWNER,"root", /* owner (not uid) is root */ KEY_COMMENT,"some comment", /* a comment */ KEY_END)); /* end of args */ ksAppendKey(ks,keyNew("user/env/alias/ls", /* a key we know we have */ KEY_END)); /* do nothing more */ ksAppendKey(ks,keyNew("user/env/alias/ls", /* same key, to compare in output */ KEY_OWNER,"root", /* set new owner (not uid) as root */ KEY_COMMENT,"new comment", /* set new comment */ KEY_END)); /* end of args */ key=keyNew("user/test//", KEY_END); /* we are providing a lot of '/' to see it being removed */ keySetName(key,"system"); keySetName(key,"user"); keySetName(key,"user:aviram"); keySetName(key,"user///abc//////def///"); keySetName(key,"user:root///aaa//////bbb///"); keyAddBaseName(key,"tmp"); keyAddBaseName(key,"////ex6///exx7///"); keySetBaseName(key,"ex8"); keySetBaseName(key,"ex9"); keyAddBaseName(key,"///exxx9///ex10///ex\\/11///"); keySetBaseName(key,"ex12"); keySetBaseName(key,"ex13///"); ksAppendKey(ks,key); ksDel(ks); printf ("finished\n"); return 0; }
int keyRel2 (const Key * key, const Key * check, KeyRelType which) { if (!key || !check) return -1; if (!key->key || !check->key) return -1; Key * cKey = keyAsCascading (key); Key * cCheck = keyAsCascading (check); Key * cKeyParent = keyDup (cKey); keySetBaseName (cKeyParent, 0); if (keyName (cKeyParent)[0] == '\0') keySetName (cKeyParent, "/"); int isBelow = 0; int isSilblingNephew = 0; isBelow = keyGetLevelsBelow (cKey, cCheck); if (!isBelow) isSilblingNephew = keyGetLevelsBelow (cKeyParent, cCheck); elektraNamespace keyNamespace = keyGetNamespace (key); elektraNamespace checkNamespace = keyGetNamespace (check); int retVal = 0; int bits = 0; for (KeyRelType type = 1; type != 0; type <<= 1) { if (type & which) ++bits; } if (bits != 1) return -1; switch (which) { case ELEKTRA_REL_BELOW_SAME_NS: if (isBelow && (keyNamespace == checkNamespace)) retVal = isBelow; break; case ELEKTRA_REL_BELOW_IGNORE_NS: if (isBelow) retVal = isBelow; break; case ELEKTRA_REL_BELOW_CASCADING_NS: if (isBelow && ((checkNamespace == KEY_NS_CASCADING) || (keyNamespace == KEY_NS_CASCADING))) retVal = isBelow; break; case ELEKTRA_REL_DIRECT_BELOW_SAME_NS: if ((isBelow == 1) && (keyNamespace == checkNamespace)) retVal = 1; break; case ELEKTRA_REL_DIRECT_BELOW_IGNORE_NS: if (isBelow == 1) retVal = 1; break; case ELEKTRA_REL_DIRECT_BELOW_CASCADING_NS: if ((isBelow == 1) && ((checkNamespace == KEY_NS_CASCADING) || (keyNamespace == KEY_NS_CASCADING))) retVal = 1; break; case ELEKTRA_REL_SILBLING_SAME_NS: if ((isSilblingNephew == 1) && (keyNamespace == checkNamespace)) retVal = 1; break; case ELEKTRA_REL_SILBLING_IGNORE_NS: if (isSilblingNephew == 1) retVal = 1; break; case ELEKTRA_REL_SILBLING_CASCADING_NS: if ((isSilblingNephew == 1) && ((checkNamespace == KEY_NS_CASCADING) || (keyNamespace == KEY_NS_CASCADING))) retVal = 1; break; case ELEKTRA_REL_NEPHEW_SAME_NS: if ((isSilblingNephew > 1) && (keyNamespace == checkNamespace)) retVal = isSilblingNephew - 1; break; case ELEKTRA_REL_NEPHEW_IGNORE_NS: if (isSilblingNephew > 1) retVal = isSilblingNephew - 1; break; case ELEKTRA_REL_NEPHEW_CASCADING_NS: if ((isSilblingNephew > 1) && ((checkNamespace == KEY_NS_CASCADING) || (keyNamespace == KEY_NS_CASCADING))) retVal = isSilblingNephew - 1; break; default: retVal = -1; break; } keyDel (cKey); keyDel (cCheck); keyDel (cKeyParent); return retVal; }
static void test_search() { printf ("Testing operation search (internal)\n"); KeySet *a = set_a(); Key *s = keyNew("user/a", KEY_END); ssize_t result; keySetName (s, "user/0"); result = ksSearchInternal (a, s); succeed_if (result == 0, "insertpos wrong"); keySetName (s, "user/a"); result = ksSearchInternal (a, s); succeed_if (result == 1, "insertpos wrong"); keySetName (s, "user/a/0"); result = ksSearchInternal (a, s); succeed_if (result == -3, "insertpos wrong"); keySetName (s, "user/a/a"); result = ksSearchInternal (a, s); succeed_if (result == 2, "insertpos wrong"); keySetName (s, "user/a/a/a"); result = ksSearchInternal (a, s); succeed_if (result == 3, "insertpos wrong"); keySetName (s, "user/a/a/b"); result = ksSearchInternal (a, s); succeed_if (result == 4, "insertpos wrong"); keySetName (s, "user/a/b"); result = ksSearchInternal (a, s); succeed_if (result == 5, "insertpos wrong"); keySetName (s, "user/a/b/a"); result = ksSearchInternal (a, s); succeed_if (result == 6, "insertpos wrong"); keySetName (s, "user/a/b/b"); result = ksSearchInternal (a, s); succeed_if (result == 7, "insertpos wrong"); keySetName (s, "user/a/c"); result = ksSearchInternal (a, s); succeed_if (result == 8, "insertpos wrong"); keySetName (s, "user/a/d"); result = ksSearchInternal (a, s); succeed_if (result == 9, "insertpos wrong"); keySetName (s, "user/a/x"); result = ksSearchInternal (a, s); succeed_if (result == -11, "insertpos wrong"); keySetName (s, "user/a/x/a"); result = ksSearchInternal (a, s); succeed_if (result == 10, "insertpos wrong"); keySetName (s, "user/a/x/b"); result = ksSearchInternal (a, s); succeed_if (result == 11, "insertpos wrong"); keySetName (s, "user/a/x/c"); result = ksSearchInternal (a, s); succeed_if (result == 12, "insertpos wrong"); keySetName (s, "user/a/x/c/a"); result = ksSearchInternal (a, s); succeed_if (result == 13, "insertpos wrong"); keySetName (s, "user/a/x/c/b"); result = ksSearchInternal (a, s); succeed_if (result == 14, "insertpos wrong"); keySetName (s, "user/x"); result = ksSearchInternal (a, s); succeed_if (result == 15, "insertpos wrong"); /* Generation of new Testcases: for (int i=0; i< 16; ++i) { s = a->array[i]; printf ("keySetName (s, \"%s\");\n", keyName(s)); printf ("result = ksSearchInternal (a, s);\n"); printf ("succeed_if (result == %zd, \"insertpos wrong\");\n\n", ksSearchInternal (a, s)); } */ keyDel (s); ksDel (a); }
static void test_modules() { printf ("Test mounting with modules\n"); KDB *kdb = kdb_new(); Key *errorKey = keyNew(0); KeySet *modules = modules_config(); succeed_if (elektraMountOpen(kdb, root_config(), modules, errorKey) == 0, "could not buildup mount"); succeed_if (elektraMountDefault(kdb, modules, errorKey) == 0, "could not mount default backend"); succeed_if (elektraMountModules(kdb, modules, errorKey) == 0, "could not mount modules"); succeed_if(output_warnings (errorKey), "warnings found"); succeed_if(output_error (errorKey), "error found"); succeed_if (kdb->split->size == 8, "size of split not correct"); Key *mp = keyNew("spec", KEY_VALUE, "root", KEY_END); compare_key(mp, kdb->split->parents[0]); keySetName(mp, "dir"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[1]); keySetName(mp, "user"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[2]); keySetName(mp, "system"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[3]); /* we cannot exactly know where resolver+dump is located *(depending on alphabet) keySetName(mp, "system/elektra/modules/"KDB_DEFAULT_RESOLVER); keySetString (mp, "modules"); compare_key(mp, kdb->split->parents[4]); */ keySetName(mp, "system/elektra"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[5]); keySetName(mp, "user/tests/simple"); keySetString (mp, "simple"); compare_key(mp, kdb->split->parents[4]); exit_if_fail (kdb->trie, "trie was not build up successfully"); // output_trie (kdb->trie); Key *searchKey = keyNew("", KEY_END); Key *rmp = keyNew("", KEY_VALUE, "root", KEY_END); elektraKeySetName(rmp, "/", KEY_CASCADING_NAME); Backend *b2 = 0; keySetName (searchKey, "user"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, rmp); Backend *backend = 0; keySetName(searchKey, "user/tests/simple"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/tests/simple/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); Key *dmp = keyNew ("", KEY_VALUE, "default", KEY_END); keySetName(searchKey, "system/elektra"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); keySetName(searchKey, "system/elektra/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); Key *mmp = keyNew ("system/elektra/modules", KEY_VALUE, "modules", KEY_END); keyAddBaseName (mmp, "default"); /* keySetName(searchKey, "system/elektra/modules/default"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 != kdb->defaultBackend, "should not be the default backend"); compare_key(b2->mountpoint, mmp); */ keyDel (mmp); keyDel (dmp); keyDel (mp); keyDel (rmp); keyDel (searchKey); kdb_del (kdb); keyDel (errorKey); ksDel (modules); }
NSS_STATUS _nss_registry_getspnam_r (const char *name, struct spwd * pw, char *buffer, size_t buflen, int *errnop) { int i; char *tmpbuf=NULL; Key *tmpkey; *errnop = ENOENT; /* Open registry connection */ registryOpen(); if(_nss_registry_finduserbyname(name) == NSS_STATUS_NOTFOUND) return NSS_STATUS_NOTFOUND; /* Yay! the users exists, lets continue */ pw->sp_namp = (char *)_nss_registry_copy_to_buffer(&buffer,&buflen,name); if(! pw->sp_namp) goto out_nomem; tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"shadowPassword"); if(!_nss_registry_isempty(tmpbuf)) { pw->sp_pwdp = (char *)_nss_registry_copy_to_buffer(&buffer,&buflen,tmpbuf); free(tmpbuf); } else { /* If password is empty, set it to an empty string..If it's still empty, fail */ pw->sp_pwdp = (char *)_nss_registry_copy_to_buffer(&buffer,&buflen,""); } if(!pw->sp_pwdp) goto out_nomem; /*tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdLastChange");*/ /* It's expected to be returned in this format * OK. It's a long and evil way to do this, but I don't have much choice. * returns last time password was changed, whether it was comment or * actual password */ tmpbuf = (char *)malloc(255); sprintf(tmpbuf, "system/users/%s/shadowPassword",pw->sp_namp); tmpkey = (Key *)malloc(sizeof(Key)); keyInit(tmpkey); keySetName(tmpkey, tmpbuf); registryStatKey(tmpkey); pw->sp_lstchg = keyGetMTime(tmpkey) / (60 * 60 * 24); keyClose(tmpkey); free(tmpkey); free(tmpbuf); tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdChangeBefore"); pw->sp_min = _nss_registry_strtol(tmpbuf,FALLBACK,&i); if (i) { _nss_registry_log(LOG_ERR,"User %s has invalid passwdChangeBefore (%s). " " Reverted to %d. Fix you registry entries.", pw->sp_namp, tmpbuf||"NULL", pw->sp_min); } if (tmpbuf != NULL) free(tmpbuf); tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdChangeAfter"); pw->sp_max = _nss_registry_strtol(tmpbuf,FALLBACK,&i); if (i) { _nss_registry_log(LOG_ERR,"User %s has invalid passwdChangeAfter (%s). " " Reverted to %d. Fix you registry entries.", pw->sp_namp, tmpbuf||"NULL", pw->sp_max); } if (tmpbuf != NULL) free(tmpbuf); tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdWarnBefore"); pw->sp_warn = _nss_registry_strtol(tmpbuf,FALLBACK,&i); if (i) { _nss_registry_log(LOG_ERR,"User %s has invalid passwdWarnBefore (%s). " " Reverted to %d. Fix you registry entries.", pw->sp_namp, tmpbuf||"NULL", pw->sp_warn); } if (tmpbuf != NULL) free(tmpbuf); tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdDisableAfter"); pw->sp_inact = _nss_registry_strtol(tmpbuf,FALLBACK,&i); /* Don't warn in this case since it seems quite normal to not have that set.. * At least on my system */ if(tmpbuf != NULL) free(tmpbuf); tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdDisabledSince"); pw->sp_expire = _nss_registry_strtol(tmpbuf,FALLBACK,&i); /* Don't warn in this case since it seems quite normal to not have that set.. * At least on my system */ if(tmpbuf != NULL) free(tmpbuf); tmpbuf = _nss_registry_get_string(REGISTRYUSER, pw->sp_namp,"passwdReserved"); pw->sp_flag = _nss_registry_strtol(tmpbuf,FALLBACK,&i); /* Don't warn in this case since it seems quite normal to not have that set.. * At least on my system */ if(tmpbuf != NULL) free(tmpbuf); /* Woo! this means it was successfull. Go on! tell everyone :) */ *errnop = 0; registryClose(); return NSS_STATUS_SUCCESS; /* Taken from nss-mysql */ out_nomem: /* if we're here, that means that the buffer is too small, so * we return ERANGE */ *errnop = ERANGE; registryClose(); return NSS_STATUS_TRYAGAIN; }
static void test_default() { printf ("Test mounting with default\n"); KDB *kdb = kdb_new(); Key *errorKey = keyNew(0); KeySet *modules = modules_config(); succeed_if (elektraMountOpen(kdb, root_config(), modules, errorKey) == 0, "could not buildup mount"); succeed_if (elektraMountDefault(kdb, modules, errorKey) == 0, "could not mount default backend"); succeed_if (kdb->split->size == 6, "size of split not correct"); Key *mp = keyNew("spec", KEY_VALUE, "root", KEY_END); compare_key(mp, kdb->split->parents[0]); keySetName(mp, "dir"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[1]); keySetName(mp, "user"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[2]); keySetName(mp, "system"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[3]); keySetName(mp, "system/elektra"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[5]); // must be last, needed later keySetName(mp, "user/tests/simple"); keySetString (mp, "simple"); compare_key(mp, kdb->split->parents[4]); succeed_if(output_warnings (errorKey), "warnings found"); succeed_if(output_error (errorKey), "error found"); exit_if_fail (kdb->trie, "trie was not build up successfully"); // output_trie (kdb->trie); Key *searchKey = keyNew("", KEY_END); Key *rmp = keyNew("", KEY_VALUE, "root", KEY_END); elektraKeySetName(rmp, "/", KEY_CASCADING_NAME); Backend *b2 = 0; keySetName (searchKey, "user"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, rmp); Backend *backend = 0; keySetName(searchKey, "user/tests/simple"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/tests/simple/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); Key *dmp = keyNew ("", KEY_VALUE, "default", KEY_END); keySetName(searchKey, "system/elektra"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); keySetName(searchKey, "system/elektra/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); keyDel (dmp); keyDel (mp); keyDel (rmp); keyDel (searchKey); kdb_del (kdb); keyDel (errorKey); ksDel (modules); }