/** * Compare 2 keys. * * The returned flags bit array has 1s (differ) or 0s (equal) for each key * meta info compared, that can be logically ORed using @c #keyswitch_t flags. * @link keyswitch_t::KEY_NAME KEY_NAME @endlink, * @link keyswitch_t::KEY_VALUE KEY_VALUE @endlink, * @link keyswitch_t::KEY_OWNER KEY_OWNER @endlink, * @link keyswitch_t::KEY_COMMENT KEY_COMMENT @endlink, * @link keyswitch_t::KEY_UID KEY_UID @endlink, * @link keyswitch_t::KEY_GID KEY_GID @endlink, * @link keyswitch_t::KEY_MODE KEY_MODE @endlink and * * @par A very simple example would be * @code Key *key1, *key; uint32_t changes; // omited key1 and key2 initialization and manipulation changes=keyCompare(key1,key2); if (changes == 0) printf("key1 and key2 are identicall\n"); if (changes & KEY_VALUE) printf("key1 and key2 have different values\n"); if (changes & KEY_UID) printf("key1 and key2 have different UID\n"); * * @endcode * * * @par Example of very powerful specific Key lookup in a KeySet: * @code KDB *handle = kdbOpen(); KeySet *ks=ksNew(0); Key *base = keyNew ("user/sw/MyApp/something", KEY_END); Key *current; uint32_t match; uint32_t interests; kdbGetByName(handle, ks, "user/sw/MyApp", 0); // we are interested only in key type and access permissions interests=(KEY_TYPE | KEY_MODE); ksRewind(ks); // put cursor in the beginning while ((curren=ksNext(ks))) { match=keyCompare(current,base); if ((~match & interests) == interests) printf("Key %s has same type and permissions of base key",keyName(current)); // continue walking in the KeySet.... } // now we want same name and/or value interests=(KEY_NAME | KEY_VALUE); // we don't really need ksRewind(), since previous loop achieved end of KeySet ksRewind(ks); while ((current=ksNext(ks))) { match=keyCompare(current,base); if ((~match & interests) == interests) { printf("Key %s has same name, value, and sync status of base key",keyName(current)); } // continue walking in the KeySet.... } keyDel(base); ksDel(ks); kdbClose (handle); * @endcode * * @return a bit array pointing the differences * @param key1 first key * @param key2 second key * @see #keyswitch_t * @ingroup keytest */ keyswitch_t keyCompare(const Key *key1, const Key *key2) { if (!key1 && !key2) return 0; if (!key1 || !key2) return KEY_NULL; keyswitch_t ret=0; ssize_t nsize1 = keyGetNameSize(key1); ssize_t nsize2 = keyGetNameSize(key2); const char *name1 = keyName(key1); const char *name2 = keyName(key2); const char *comment1 = keyComment(key1); const char *comment2 = keyComment(key2); const char *owner1 = keyOwner(key1); const char *owner2 = keyOwner(key2); const void *value1 = keyValue(key1); const void *value2 = keyValue(key2); ssize_t size1 = keyGetValueSize(key1); ssize_t size2 = keyGetValueSize(key2); if (keyGetUID(key1) != keyGetUID(key2)) ret|=KEY_UID; if (keyGetGID(key1) != keyGetGID(key2)) ret|=KEY_GID; if (keyGetMode(key1)!= keyGetMode(key2)) ret|=KEY_MODE; if (nsize1 != nsize2) ret|=KEY_NAME; if (strcmp(name1, name2)) ret|=KEY_NAME; if (strcmp(comment1, comment2)) ret|=KEY_COMMENT; if (strcmp(owner1, owner2)) ret|=KEY_OWNER; if (size1 != size2) ret|=KEY_VALUE; if (memcmp(value1, value2, size1)) ret|=KEY_VALUE; return ret; }
static void elektraDropCurrentKey (KeySet * ks, Key * warningKey, const Backend * curHandle, const char * msg) { const Key * k = ksCurrent (ks); const size_t sizeOfStaticText = 100; char * warningMsg = elektraMalloc (keyGetNameSize (curHandle->mountpoint) + keyGetValueSize (curHandle->mountpoint) + keyGetNameSize (k) + strlen (msg) + sizeOfStaticText); strcpy (warningMsg, "drop key "); const char * name = keyName (k); if (name) { strcat (warningMsg, name); } else { strcat (warningMsg, "(no name)"); } strcat (warningMsg, " not belonging to "); strcat (warningMsg, keyName (curHandle->mountpoint)); strcat (warningMsg, " with name "); strcat (warningMsg, keyString (curHandle->mountpoint)); strcat (warningMsg, " because "); strcat (warningMsg, msg); ELEKTRA_ADD_WARNING (79, warningKey, warningMsg); elektraFree (warningMsg); cursor_t c = ksGetCursor (ks); keyDel (elektraKsPopAtCursor (ks, c)); ksSetCursor (ks, c); elektraKsPrev (ks); // next ksNext() will point correctly again }
// keyRel2 helper, turns key into a cascading key ( removes namespace) Key * keyAsCascading (const Key * key) { if (keyName (key)[0] == '/') { return keyDup (key); } else { const char * name = keyName (key); const char * ptr = strchr (name, '/'); if (!ptr) { return keyNew ("/", KEY_CASCADING_NAME, KEY_END); } else { ssize_t length = keyGetNameSize (key); if ((ptr - name) == (length - 1)) { return keyNew ("/", KEY_CASCADING_NAME, KEY_END); } else { return keyNew (ptr, KEY_CASCADING_NAME, KEY_END); } } } }
static KeySet * getGlobKeys (Key * parentKey, KeySet * keys, enum GlobDirection direction) { KeySet * glob = ksNew (0, KS_END); Key * k = 0; size_t parentsize = keyGetNameSize (parentKey); Key * userGlobConfig = 0; Key * systemGlobConfig = 0; Key * userDirGlobConfig = 0; Key * systemDirGlobConfig = 0; userGlobConfig = keyNew ("user/glob", KEY_END); systemGlobConfig = keyNew ("system/glob", KEY_END); switch (direction) { case GET: userDirGlobConfig = keyNew ("user/glob/get", KEY_END); systemDirGlobConfig = keyNew ("system/glob/get", KEY_END); break; case SET: userDirGlobConfig = keyNew ("user/glob/set", KEY_END); systemDirGlobConfig = keyNew ("system/glob/set", KEY_END); break; } while ((k = ksNext (keys)) != 0) { /* use only glob keys for the current direction */ if (keyIsDirectBelow (userGlobConfig, k) || keyIsDirectBelow (systemGlobConfig, k) || keyIsDirectBelow (userDirGlobConfig, k) || keyIsDirectBelow (systemDirGlobConfig, k)) { keySetMeta (k, "glob/flags", getGlobFlags (keys, k)); /* Look if we have a string */ size_t valsize = keyGetValueSize (k); if (valsize < 2) continue; /* We now know we want that key. Dup it to not change the configuration. */ Key * ins = keyDup (k); /* Now look if we want cascading for the key */ if (keyString (k)[0] == '/') { char * newstring = elektraMalloc (valsize + parentsize); strcpy (newstring, keyName (parentKey)); strcat (newstring, keyString (k)); keySetString (ins, newstring); elektraFree (newstring); } ksAppendKey (glob, ins); } } keyDel (userGlobConfig); keyDel (systemGlobConfig); keyDel (userDirGlobConfig); keyDel (systemDirGlobConfig); return glob; }
static int elektraResolveEnvUser(resolverHandle *p) { const char* owner = getenv("USER"); if (!owner || !strcmp(owner, "")) { return 0; } Key *canonify = keyNew("user", KEY_END); keyAddName(canonify, owner); size_t dirnameSize = sizeof(KDB_DB_HOME "/") + keyGetNameSize(canonify) + sizeof("/" KDB_DB_USER); p->dirname= elektraMalloc (dirnameSize); strcpy (p->dirname, KDB_DB_HOME "/"); strcat (p->dirname, keyName(canonify) +5); // cut user/ if (p->path[0] != '/') { strcat (p->dirname, "/" KDB_DB_USER); } keyDel(canonify); return 1; }
/** * @brief Takes the first key and cuts off this common part * for all other keys, instead name will be prepended * * @return a new allocated keyset with keys in user namespace. * * The first key is removed in the resulting keyset. */ KeySet* elektraRenameKeys(KeySet *config, const char* name) { Key *root; Key *cur; ssize_t rootSize = 0; ksRewind(config); root = ksNext (config); rootSize = keyGetNameSize(root); keyDel (ksLookup (config, root, KDB_O_POP)); KeySet *newConfig = ksNew(ksGetSize(config), KS_END); if (rootSize == -1) return newConfig; while ((cur = ksPop(config)) != 0) { Key *dupKey = keyDup(cur); keySetName(dupKey, name); keyAddName(dupKey, keyName(cur)+rootSize-1); ksAppendKey(newConfig, dupKey); keyDel(cur); } return newConfig; }
static void test_lookupNoascading () { printf ("Test lookup without cascading\n"); Key * specKey = keyNew ("/abc", KEY_CASCADING_NAME, KEY_END); Key * d = keyDup (specKey); keySetString (d, "dup"); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if_same_string (keyName (d), "/abc"); succeed_if (!keyCmp (d, specKey), "comparision to duplicate failed"); succeed_if_same_string (keyName (d), "/abc"); succeed_if_same_string (keyName (specKey), "/abc"); KeySet * ks = ksNew (20, d, KS_END); Key * k = ksLookup (ks, specKey, KDB_O_NOCASCADING); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if (k != 0, "did not find cascading key"); succeed_if (k != specKey, "should not be specKey"); succeed_if (k == d, "should be dup key"); Key * a = keyNew (keyName (specKey), KEY_CASCADING_NAME, KEY_VALUE, "a", KEY_END); ksAppendKey (ks, a); for (int i = 0; i < 5; ++i) { k = ksLookup (ks, specKey, KDB_O_NOCASCADING); succeed_if (keyGetNameSize (specKey) == 5, "size of spec key wrong"); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if (k != 0, "did not find cascading key"); succeed_if (k != specKey, "should not be specKey"); succeed_if (k == a, "should be dup key"); // search without cascading k = ksLookup (ks, specKey, 0); succeed_if (keyGetNameSize (specKey) == 5, "size of spec key wrong"); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if (k != 0, "did not find cascading key"); succeed_if (k != specKey, "should not be specKey"); succeed_if (k == a, "should be dup key"); } ksDel (ks); keyDel (specKey); }
/** * @internal * * Compare 2 keys. * * The returned flags bit array has 1s (differ) or 0s (equal) for each key * meta info compared, that can be logically ORed using @c #keyswitch_t flags. * @link keyswitch_t::KEY_NAME KEY_NAME @endlink, * @link keyswitch_t::KEY_VALUE KEY_VALUE @endlink, * @link keyswitch_t::KEY_OWNER KEY_OWNER @endlink, * @link keyswitch_t::KEY_COMMENT KEY_COMMENT @endlink, * @link keyswitch_t::KEY_META KEY_META @endlink (will be set in addition to owner and comment), * * @par A very simple example would be * @code Key *key1, *key; uint32_t changes; // omited key1 and key2 initialization and manipulation changes=keyCompare(key1,key2); if (changes == 0) printf("key1 and key2 are identicall\n"); if (changes & KEY_VALUE) printf("key1 and key2 have different values\n"); if (changes & KEY_UID) printf("key1 and key2 have different UID\n"); * * @endcode * * * @par Example of very powerful specific Key lookup in a KeySet: * @code Key *base = keyNew ("/sw/MyApp/something", KEY_END); KDB *handle = kdbOpen(base); KeySet *ks=ksNew(0, KS_END); Key *current; uint32_t match; uint32_t interests; kdbGet(handle, ks, base); // we are interested only in key type and access permissions interests=(KEY_TYPE | KEY_MODE); ksRewind(ks); // put cursor in the beginning while ((curren=ksNext(ks))) { match=keyCompare(current,base); if ((~match & interests) == interests) printf("Key %s has same type and permissions of base key",keyName(current)); // continue walking in the KeySet.... } // now we want same name and/or value interests=(KEY_NAME | KEY_VALUE); // we don't really need ksRewind(), since previous loop achieved end of KeySet ksRewind(ks); while ((current=ksNext(ks))) { match=keyCompare(current,base); if ((~match & interests) == interests) { printf("Key %s has same name, value, and sync status of base key",keyName(current)); } // continue walking in the KeySet.... } ksDel(ks); kdbClose (handle, base); keyDel(base); * @endcode * * @return a bit array pointing the differences * @param key1 first key * @param key2 second key * @see #keyswitch_t * @ingroup keytest */ keyswitch_t keyCompare (const Key * key1, const Key * key2) { if (!key1 && !key2) return 0; if (!key1 || !key2) return KEY_NULL; keyswitch_t ret = 0; ssize_t nsize1 = keyGetNameSize (key1); ssize_t nsize2 = keyGetNameSize (key2); const char * name1 = keyName (key1); const char * name2 = keyName (key2); const Key * comment1 = keyGetMeta (key1, "comment"); const Key * comment2 = keyGetMeta (key2, "comment"); const char * owner1 = keyOwner (key1); const char * owner2 = keyOwner (key2); const void * value1 = keyValue (key1); const void * value2 = keyValue (key2); ssize_t size1 = keyGetValueSize (key1); ssize_t size2 = keyGetValueSize (key2); // TODO: might be (binary) by chance if (strcmp (keyString (comment1), keyString (comment2))) ret |= KEY_COMMENT; if (strcmp (owner1, owner2)) ret |= KEY_OWNER; if (keyCompareMeta (key1, key2)) ret |= KEY_META; if (nsize1 != nsize2) ret |= KEY_NAME; else if (!name1 || !name2) ret |= KEY_NAME; else if (strcmp (name1, name2)) ret |= KEY_NAME; if (size1 != size2) ret |= KEY_VALUE; else if (!value1 || !value2) ret |= KEY_VALUE; else if (memcmp (value1, value2, size1)) ret |= KEY_VALUE; // TODO: rewind metadata to previous position return ret; }
static int saveTree (augeas * augeasHandle, KeySet * ks, const char * lensPath, Key * parentKey) { int ret = 0; size_t prefixSize = keyGetNameSize (parentKey) - 1; size_t arraySize = ksGetSize (ks); Key ** keyArray = calloc (ksGetSize (ks), sizeof (Key *)); ret = elektraKsToMemArray (ks, keyArray); if (ret < 0) goto memoryerror; qsort (keyArray, arraySize, sizeof (Key *), keyCmpOrderWrapper); /* convert the Elektra KeySet to an Augeas tree */ for (size_t i = 0; i < arraySize; i++) { Key * key = keyArray[i]; char * nodeName; ret = asprintf (&nodeName, AUGEAS_TREE_ROOT "%s", (keyName (key) + prefixSize)); if (ret < 0) goto memoryerror; aug_set (augeasHandle, nodeName, keyString (key)); elektraFree (nodeName); } elektraFree (keyArray); /* remove keys not present in the KeySet */ struct OrphanSearch * data = elektraMalloc (sizeof (struct OrphanSearch)); if (!data) return -1; data->ks = ks; data->parentKey = parentKey; ret = foreachAugeasNode (augeasHandle, AUGEAS_TREE_ROOT, &removeOrphan, data); elektraFree (data); /* build the tree */ ret = aug_text_retrieve (augeasHandle, lensPath, AUGEAS_CONTENT_ROOT, AUGEAS_TREE_ROOT, AUGEAS_OUTPUT_ROOT); if (ret < 0) { /* report the augeas specific error */ ELEKTRA_SET_ERROR (85, parentKey, getAugeasError (augeasHandle)); } return ret; memoryerror: elektraFree (keyArray); ELEKTRA_SET_ERROR (87, parentKey, "Unable to allocate memory while saving the augeas tree"); return -1; }
/** * Check if the key check is below the key key or not. * * Example: @verbatim key user/sw/app check user/sw/app/key @endverbatim * * returns true because check is below key * * Example: @verbatim key user/sw/app check user/sw/app/folder/key @endverbatim * * returns also true because check is indirect below key * * @param key the key object to work with * @param check the key to find the relative position of * @return 1 if check is below key * @return 0 if it is not below or if it is the same key * @see keySetName(), keyGetName(), keyIsDirectBelow() * @ingroup keytest * */ int keyIsBelow(const Key *key, const Key *check) { const char * keyname = 0; const char * checkname = 0; ssize_t keysize = 0; ssize_t checksize = 0; if (!key || !check) return -1; keyname = keyName(key); checkname = keyName(check); keysize = keyGetNameSize(key); checksize = keyGetNameSize(check); if (keysize > checksize + 1) return 0; if (strncmp (keyname, checkname, keysize - 1)) return 0; if (checkname[keysize - 1] != '/') return 0; return 1; }
/** * Generate a C-Style key and stream it. * * This keyset can be used to include as c-code for * applikations using elektra. * * @param key the key object to work with * @param stream the file pointer where to send the stream * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO * @retval 1 on success * @ingroup stream */ int keyGenerate(const Key * key, FILE *stream, option_t options) { size_t s; char * str; size_t c; char * com; size_t n; char * nam; n = keyGetNameSize (key); if (n>1) { nam = (char*) elektraMalloc (n); if (nam == NULL) return -1; keyGetName (key, nam, n); fprintf(stream,"\tkeyNew (\"%s\"", nam); elektraFree (nam); } s = keyGetValueSize (key); if (s>1) { str = (char*) elektraMalloc (s); if (str == NULL) return -1; if (keyIsBinary(key)) keyGetBinary(key, str, s); else keyGetString (key, str, s); fprintf(stream,", KEY_VALUE, \"%s\"", str); elektraFree (str); } c = keyGetCommentSize (key); if (c>1) { com = (char*) elektraMalloc (c); if (com == NULL) return -1; keyGetComment (key, com, c); fprintf(stream,", KEY_COMMENT, \"%s\"", com); elektraFree (com); } if (! (keyGetMode(key) == 0664 || (keyGetMode(key) == 0775))) { fprintf(stream,", KEY_MODE, 0%3o", keyGetMode(key)); } fprintf(stream,", KEY_END)"); if (options == 0) return 1; /* dummy to make icc happy */ return 1; }
/** * Check if the key check is direct below the key key or not. * @verbatim Example: key user/sw/app check user/sw/app/key returns true because check is below key Example: key user/sw/app check user/sw/app/folder/key does not return true, because there is only a indirect relation @endverbatim * * @param key the key object to work with * @param check the key to find the relative position of * @return 1 if check is below key * @return 0 if it is not below or if it is the same key * @return -1 on null pointer * @see keyIsBelow(), keySetName(), keyGetName() * @ingroup keytest * */ int keyIsDirectBelow(const Key *key, const Key *check) { const char * checkname = 0; ssize_t keysize = 0; if (!key || !check) return -1; checkname = keyName(check); keysize = keyGetNameSize(key); if (!keyIsBelow(key, check)) return 0; if (strchr(checkname + keysize, '/')) return 0; return 1; }
/** * @brief get relative position of key based on parentKey * * @param cur the key below parentKey we want to get the relative basename of * @param parentKey the key that defines the root/base * * @return a pointer to the name of the key cur */ const char * elektraKeyGetRelativeName (Key const * cur, Key const * parentKey) { size_t offset = 0; if (strcmp (keyName (parentKey), "/")) { offset = keyGetNameSize (parentKey); if (keyName (parentKey)[0] == '/' && keyName (cur)[0] != '/') { offset += strstr (keyName (cur), keyName (parentKey)) - keyName (cur); } } return keyName (cur) + offset; }
static int saveTree(augeas* augeasHandle, KeySet* ks, const char* lensPath, Key *parentKey) { int ret = 0; size_t prefixSize = keyGetNameSize (parentKey) - 1; size_t arraySize = ksGetSize (ks); Key **keyArray = calloc (ksGetSize(ks), sizeof (Key *)); ret = elektraKsToMemArray (ks, keyArray); if (ret < 0) { free (keyArray); return -1; } qsort (keyArray, arraySize, sizeof(Key *), keyCmpOrderWrapper); /* convert the Elektra KeySet to an Augeas tree */ for (size_t i = 0; i < arraySize; i++) { Key *key = keyArray[i]; char *nodeName; asprintf (&nodeName, AUGEAS_TREE_ROOT "%s", (keyName (key) + prefixSize)); aug_set (augeasHandle, nodeName, keyString (key)); free (nodeName); } free (keyArray); /* remove keys not present in the KeySet */ struct OrphanSearch *data = malloc (sizeof(struct OrphanSearch)); if (!data) return -1; data->ks = ks; data->parentKey = parentKey; foreachAugeasNode (augeasHandle, AUGEAS_TREE_ROOT, &removeOrphan, data); free (data); /* build the tree */ ret = aug_text_retrieve (augeasHandle, lensPath, AUGEAS_CONTENT_ROOT, AUGEAS_TREE_ROOT, AUGEAS_OUTPUT_ROOT); return ret; }
static void elektraResolveUsingHome (ElektraResolved * handle, const char * home, short addPostfix) { Key * canonify = keyNew ("user", KEY_END); keyAddName (canonify, home); size_t dirnameSize = keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER); char * dir = elektraMalloc (dirnameSize); strcpy (dir, keyName (canonify) + 4); // cut user, leave slash if (addPostfix && handle->relPath[0] != '/') { strcat (dir, "/" KDB_DB_USER); } handle->dirname = dir; keyDel (canonify); }
static void elektraResolveUsingHome (resolverHandle * p, const char * home, bool addPostfix) { size_t dirnameSize = 0; Key * canonify = keyNew ("user", KEY_END); keyAddName (canonify, home); dirnameSize = keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER); p->dirname = elektraMalloc (dirnameSize); strcpy (p->dirname, keyName (canonify) + 4); // cut user, but leave slash if (addPostfix && p->path[0] != '/') { strcat (p->dirname, "/" KDB_DB_USER); } keyDel (canonify); }
/** * Generate a C-Style key and stream it. * * This keyset can be used to include as c-code for * applikations using elektra. * * @param key the key object to work with * @param stream the file pointer where to send the stream * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO * @retval 1 on success * @ingroup stream */ int keyGenerate (const Key * key, FILE * stream, option_t options) { size_t n = keyGetNameSize (key); if (n > 1) { char * nam = (char *) elektraMalloc (n); if (nam == NULL) return -1; keyGetName (key, nam, n); fprintf (stream, "\tkeyNew (\"%s\"", nam); elektraFree (nam); } size_t s = keyGetValueSize (key); if (s > 1) { char * str = (char *) elektraMalloc (s); if (str == NULL) return -1; if (keyIsBinary (key)) { keyGetBinary (key, str, s); fprintf (stream, ", KEY_SIZE, \"%zd\"", keyGetValueSize (key)); } else { keyGetString (key, str, s); } fprintf (stream, ", KEY_VALUE, \"%s\"", str); elektraFree (str); } const Key * meta; Key * dup = keyDup (key); keyRewindMeta (dup); while ((meta = keyNextMeta (dup))) { fprintf (stream, ", KEY_META, \"%s\", \"%s\"", keyName (meta), keyString (meta)); } keyDel (dup); fprintf (stream, ", KEY_END)"); if (options == 0) return 1; /* dummy to make icc happy */ return 1; }
/** * Lookups a backend inside the trie. * * @return the backend if found * @return 0 otherwise * @param trie the trie object to work with * @param key the name of this key will be looked up * @ingroup trie */ Backend* elektraTrieLookup(Trie *trie, const Key *key) { char *where=0; Backend *ret=0; size_t len=0; if (!key) return 0; if (!trie) return 0; len = keyGetNameSize(key) + 1; if (len == 1) return 0; // would crash otherwise where = elektraMalloc(len); strncpy(where, keyName(key), len); where[len-2] = '/'; ret = elektraTriePrefixLookup(trie,where); elektraFree(where); return ret; }
static void test_keyName (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = metaTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); const char * name = "user/tests/storage/a"; Key * found = ksLookupByName (ks, name, 0); succeed_if (found, "did not find key"); ssize_t nameSize = keyGetNameSize (found); succeed_if (elektraStrNCmp (name, keyName (found), nameSize) == 0, "wrong Key name"); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
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; }
// keyRel2 helper, turns key into a cascading key ( removes namespace) Key * keyAsCascading (const Key * key) { if (keyName (key)[0] == '/') { return keyDup (key); } else { elektraNamespace ns = keyGetNamespace (key); if (ns == KEY_NS_META || ns == KEY_NS_EMPTY || ns == KEY_NS_NONE) { // For metakeys or keys without namespace just prefix the keyname with a "/" Key * cKey = keyNew ("/", KEY_CASCADING_NAME, KEY_END); keyAddName (cKey, keyName (key)); return cKey; } else { // Skip namespace const char * name = keyName (key); const char * ptr = strchr (name, '/'); if (!ptr) { return keyNew ("/", KEY_CASCADING_NAME, KEY_END); } else { ssize_t length = keyGetNameSize (key); if ((ptr - name) == (length - 1)) { return keyNew ("/", KEY_CASCADING_NAME, KEY_END); } else { return keyNew (ptr, KEY_CASCADING_NAME, KEY_END); } } } } }
static int elektraResolveEnvUser (ElektraResolved * handle) { const char * user = getenv ("USER"); if (!user || !strcmp (user, "")) { return 0; } Key * canonify = keyNew ("user", KEY_END); keyAddName (canonify, user); size_t homeSize = sizeof (KDB_DB_HOME "/") + keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER); char * homeBuf = elektraMalloc (homeSize); strcpy (homeBuf, KDB_DB_HOME "/"); strcat (homeBuf, keyName (canonify) + 5); // cut user/ if (handle->relPath[0] != '/') { strcat (homeBuf, "/" KDB_DB_USER); } keyDel (canonify); handle->dirname = homeBuf; return 1; }
int keyIsBelow (const Key * key, const Key * check) { const char * keyname = 0; const char * checkname = 0; const char * ukeyname = 0; const char * ucheckname = 0; ssize_t keysize = 0; ssize_t checksize = 0; ssize_t ukeysize = 0; ssize_t uchecksize = 0; if (!key || !check) return -1; keyname = keyName (key); checkname = keyName (check); ukeyname = keyUnescapedName (key); ucheckname = keyUnescapedName (check); keysize = keyGetNameSize (key); checksize = keyGetNameSize (check); ukeysize = keyGetUnescapedNameSize (key); uchecksize = keyGetUnescapedNameSize (check); if (!strcmp (checkname, "/")) return 0; if (!strcmp (keyname, "/")) { if (checkname[0] == '/') return 1; if (strchr (checkname, '/')) return 1; } else if (checkname[0] == '/') { if (keyname[0] == '/') { if (!strncmp (keyname, checkname, keysize - 1)) { if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize) { return 1; } } } else { size_t size = 0; char * ptr = (char *)keyname; ptr = keyNameGetOneLevel (ptr, &size); if (size == (size_t)keysize) { return 1; } keyname += size; keysize = elektraStrLen (keyname); ptr = strrchr (ukeyname, '\0'); ukeysize -= (ptr - ukeyname); if (!strncmp (keyname, checkname, keysize - 1)) { if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize) { return 1; } } } } else if (keyname[0] == '/') { size_t size = 0; char * ptr = (char *)checkname; ptr = keyNameGetOneLevel (ptr, &size); if (size == (size_t)checksize) { return 0; } checkname += size; checksize = elektraStrLen (checkname); ptr = strrchr (ucheckname, '\0'); uchecksize -= (ptr - ucheckname); ucheckname = ptr; if (!strncmp (keyname, checkname, keysize - 1)) { if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize) { return 1; } } } else if (!strncmp (keyname, checkname, keysize - 1)) { if ((ucheckname[ukeysize - 1] == '\0') && (uchecksize > ukeysize)) return 1; } return 0; }
static CondResult evalCondition (const Key * curKey, const char * leftSide, Comparator cmpOp, const char * rightSide, const char * condition, const Key * suffixList, KeySet * ks, Key * parentKey) { char * lookupName = NULL; char * compareTo = NULL; Key * key; int len; long result = 0; if (rightSide) { if (rightSide[0] == '\'') { // right side of the statement is a literal enclosed by '' char * endPos = strchr (rightSide + 1, '\''); if (!endPos) { result = ERROR; goto Cleanup; } if (elektraRealloc ((void **) &compareTo, endPos - rightSide) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } memset (compareTo, 0, endPos - rightSide); strncat (compareTo, rightSide + 1, endPos - rightSide - 1); } else if (rightSide && elektraStrLen (rightSide) > 1) { // not a literal, it has to be a key if (rightSide[0] == '@') len = keyGetNameSize (parentKey) + elektraStrLen (rightSide); else if (!strncmp (rightSide, "..", 2) || (rightSide[0] == '.')) len = keyGetNameSize (curKey) + elektraStrLen (rightSide); else len = elektraStrLen (rightSide); if (elektraRealloc ((void **) &lookupName, len) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } if (rightSide[0] == '@') snprintf (lookupName, len, "%s/%s", keyName (parentKey), rightSide + 1); else if (rightSide[0] == '.') // either starts with . or .., doesn't matter at this point snprintf (lookupName, len, "%s/%s", keyName (curKey), rightSide); else snprintf (lookupName, len, "%s", rightSide); key = ksLookupByName (ks, lookupName, 0); if (!key) { if (!keyGetMeta (parentKey, "error")) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found but is required for the evaluation of %s", lookupName, condition); } result = FALSE; goto Cleanup; } if (elektraRealloc ((void **) &compareTo, keyGetValueSize (key)) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } strcpy (compareTo, keyString (key)); } } if (leftSide[0] == '@') len = keyGetNameSize (parentKey) + elektraStrLen (leftSide); else if (!strncmp (leftSide, "..", 2) || (leftSide[0] == '.')) len = keyGetNameSize (curKey) + elektraStrLen (leftSide); else len = elektraStrLen (leftSide); if (elektraRealloc ((void **) &lookupName, len) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } if (leftSide[0] == '@') snprintf (lookupName, len, "%s/%s", keyName (parentKey), leftSide + 1); else if (leftSide[0] == '.') // either . or .., doesn't matter here snprintf (lookupName, len, "%s/%s", keyName (curKey), leftSide); else snprintf (lookupName, len, "%s", leftSide); key = ksLookupByName (ks, lookupName, 0); if (cmpOp == NEX) { if (key) result = FALSE; else result = TRUE; goto Cleanup; } if (!key && cmpOp != OR && cmpOp != AND) { if (!keyGetMeta (parentKey, "error")) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found but is required for the evaluation of %s", lookupName, condition); } result = FALSE; goto Cleanup; } long ret; if (cmpOp == OR || cmpOp == AND) ret = compareStrings (leftSide, rightSide, NULL); else ret = compareStrings (keyString (key), compareTo, suffixList); switch (cmpOp) { case EQU: if (!ret) result = TRUE; break; case NOT: if (ret) result = TRUE; break; case LT: if (ret < 0) result = TRUE; break; case LE: if (ret <= 0) result = TRUE; break; case GT: if (ret > 0) result = TRUE; break; case GE: if (ret >= 0) result = TRUE; break; case SET: keySetString (key, compareTo); result = TRUE; break; case AND: if (ret == 0 && !strcmp (leftSide, "'1'")) result = TRUE; break; case OR: if (!strcmp (leftSide, "'1'") || (rightSide && !strcmp (rightSide, "'1'"))) result = TRUE; break; default: result = ERROR; break; } // freeing allocated heap Cleanup: if (lookupName) elektraFree (lookupName); if (compareTo) elektraFree (compareTo); return result; }
/** * Output every information of a single key depending on options. * * The format is not very strict and only intend to be read * by human eyes for debugging purposes. Don't rely on the * format in your applications. * * @param k the key object to work with * @param stream the file pointer where to send the stream * @param options see text above * @see ksOutput() * @retval 1 on success * @retval -1 on allocation errors * @ingroup stream */ int keyOutput (const Key * k, FILE *stream, option_t options) { time_t t; size_t s; char * tmc; char * str; size_t c; char * com; size_t n; char * nam; n = keyGetNameSize (k); if (n>1) { nam = (char*) elektraMalloc (n); if (nam == NULL) return -1; keyGetName (k, nam, n); fprintf(stream,"Name[%d]: %s : ", (int)n, nam); elektraFree (nam); } s = keyGetValueSize (k); if (options & KEY_VALUE && s>1) { str = (char*) elektraMalloc (s); if (str == NULL) return -1; if (keyIsBinary(k)) { /* char * bin; bin = (char*) elektraMalloc (s*3+1); keyGetBinary(k, str, s); kdbbEncode (str, s, bin); elektraFree (bin); */ keyGetBinary (k, str, s); fprintf(stream,"Binary[%d]: %s : ", (int)s, str); } else { keyGetString (k, str, s); fprintf(stream,"String[%d]: %s : ", (int)s, str); } elektraFree (str); } c = keyGetCommentSize (k); if (options & KEY_COMMENT && c>1) { com = (char*) elektraMalloc (c); if (com == NULL) return -1; keyGetComment (k, com, c); fprintf(stream,"Comment[%d]: %s : ", (int)c, com); elektraFree (com); } if (options & KDB_O_SHOWMETA) fprintf(stream," : "); if (options & KEY_UID) fprintf(stream,"UID: %d : ", (int)keyGetUID (k)); if (options & KEY_GID) fprintf(stream,"GID: %d : ", (int)keyGetGID (k)); if (options & KEY_MODE) fprintf(stream,"Mode: %o : ", (int)keyGetMode (k)); if (options & KEY_ATIME) { t=keyGetATime(k); tmc = ctime (& t); tmc[24] = '\0'; fprintf(stream,"ATime: %s : ", tmc); } if (options & KEY_MTIME) { t=keyGetMTime(k); tmc = ctime (& t); tmc[24] = '\0'; fprintf(stream,"MTime: %s : ", tmc); } if (options & KEY_CTIME) { t=keyGetCTime(k); tmc = ctime (& t); tmc[24] = '\0'; fprintf(stream,"CTime: %s : ", tmc); } if (options & KDB_O_SHOWFLAGS) { if (!(options & KDB_O_SHOWMETA)) fprintf(stream, " "); fprintf (stream,"Flags: "); if (keyIsBinary(k)) fprintf(stream,"b"); if (keyIsString(k)) fprintf(stream,"s"); if (keyIsInactive(k)) fprintf(stream,"i"); if (keyNeedSync(k)) fprintf(stream,"s"); } fprintf(stream,"\n"); return 1; }
static int evalCondition(const char *leftSide, Comparator cmpOp, const char *rightSide, KeySet *ks, Key *parentKey) { char *lookupName = NULL; char *compareTo = NULL; Key *key; int len; long result = 0; if(rightSide[0] == '\'') { char *endPos = strchr(rightSide+1, '\''); if(!endPos) { result = -1; goto Cleanup; } if(elektraRealloc((void **)&compareTo, endPos-rightSide) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } memset(compareTo, 0, endPos-rightSide); strncat(compareTo, rightSide+1, endPos-rightSide-1); } else if(rightSide && elektraStrLen(rightSide) > 1) { len = keyGetNameSize(parentKey)+elektraStrLen(rightSide); if(elektraRealloc((void **)&lookupName, len) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } snprintf(lookupName, len, "%s/%s", keyName(parentKey), rightSide); key = ksLookupByName(ks, lookupName, 0); if(!key) { ELEKTRA_SET_ERRORF(133, parentKey, "Key %s doesn't exist", lookupName); result = -1; goto Cleanup; } if(elektraRealloc((void **)&compareTo, keyGetValueSize(key)) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } strcpy(compareTo, keyString(key)); } len = keyGetNameSize(parentKey)+elektraStrLen(leftSide); if(elektraRealloc((void **)&lookupName, len) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } snprintf(lookupName, len, "%s/%s", keyName(parentKey), leftSide); key = ksLookupByName(ks, lookupName, 0); if(!key) { ELEKTRA_SET_ERRORF(133, parentKey, "Key %s doesn't exist", lookupName); result = -1; goto Cleanup; } long ret; ret = compareStrings(keyString(key), compareTo); switch(cmpOp) { case EQU: if(!ret) result = 1; break; case NOT: if(ret) result = 1; break; case LT: if(ret < 0) result = 1; break; case LE: if(ret <= 0) result = 1; break; case GT: if(ret > 0) result = 1; break; case GE: if(ret >= 0) result = 1; break; case SET: keySetString(key, compareTo); result = 1; break; default: result = -1; break; } //freeing allocated heap Cleanup: if(lookupName) elektraFree(lookupName); if(compareTo) elektraFree(compareTo); return result; }
/** * @internal * * Calculates the common parent to all keys in @p ks. * * This is a c-helper function, you need not implement it in bindings. * * Given the @p ks KeySet, calculates the parent name for all the keys. * So if @p ks contains this keys: * * @code * system/sw/xorg/Monitors/Monitor1/vrefresh * system/sw/xorg/Monitors/Monitor1/hrefresh * system/sw/xorg/Devices/Device1/driver * system/sw/xorg/Devices/Device1/mode * @endcode * * The common parent is @p system/sw/xorg . * * On the other hand, if we have this KeySet: * * @code * system/some/thing * system/other/thing * user/unique/thing * @endcode * * No common parent is possible, so @p returnedCommonParent will contain nothing. * * @param working the Keyset to work with * @param returnedCommonParent a pre-allocated buffer that will receive the * common parent, if found * @param maxSize size of the pre-allocated @p returnedCommonParent buffer * @return size in bytes of the parent name, or 0 if there is no common parent, * or -1 to indicate an error, then @p errno must be checked. */ ssize_t ksGetCommonParentName (const KeySet * working, char * returnedCommonParent, size_t maxSize) { size_t parentSize = 0; Key * current = 0; cursor_t cinit; KeySet * ks; ssize_t sMaxSize; if (maxSize > SSIZE_MAX) return -1; sMaxSize = maxSize; cinit = ksGetCursor (working); ks = (KeySet *)working; if (ksGetSize (ks) < 1) return 0; ksRewind (ks); current = ksNext (ks); if (keyGetNameSize (current) > sMaxSize) { /*errno=KDB_ERR_TRUNC;*/ returnedCommonParent[0] = 0; return -1; } strcpy (returnedCommonParent, keyName (current)); parentSize = elektraStrLen (returnedCommonParent); while (*returnedCommonParent) { ksRewind (ks); while ((current = ksNext (ks)) != 0) { /* Test if a key doesn't match */ if (memcmp (returnedCommonParent, keyName (current), parentSize - 1)) break; } if (current) { /* some key failed to be a child */ /* parent will be the parent of current parent... */ char * delim = 0; // TODO: does not honor escaped characters if ((delim = strrchr (returnedCommonParent, KDB_PATH_SEPARATOR))) { *delim = 0; parentSize = elektraStrLen (returnedCommonParent); } else { *returnedCommonParent = 0; parentSize = 0; break; /* Better don't make comparison with parentSize-1 now */ } } else { /* All keys matched (current==0) */ /* We have our common parent to return in commonParent */ ksSetCursor (ks, cinit); return parentSize; } } ksSetCursor (ks, cinit); return parentSize; /* if reached, will be zero */ }