1 /***************************************************************************
2 keytest.c - Methods for Key manipulation
4 begin : Fri Sep 26 2008
5 copyright : (C) 2008 by Markus Raab
6 email : elektra@markus-raab.org
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the BSD License (revised). *
14 ***************************************************************************/
18 * @defgroup keytest Key :: Methods for Making Tests
19 * @brief Methods to do various tests on Keys
35 #if DEBUG && HAVE_STDIO_H
52 #include "kdbprivate.h"
57 * Ask if key is marked for stat only.
59 * Ask if the key will be stat instead of get it from the key database
60 * completely doing kdbGetKey() or kdbGet(). This is useful
61 * if you are not interested in the value, comment or key type.
63 * @see keyStat(), kdbGet()
64 * @param key the key object to work with
65 * @return 1 if it is marked, 0 otherwise
66 * @return -1 on NULL pointer
69 int keyNeedStat(const Key *key)
73 return (key->flags & KEY_FLAG_STAT) == KEY_FLAG_STAT;
79 * Test if a key needs to be synced to backend storage.
81 * If any key modification took place the key will be flagged with
82 * KEY_FLAG_SYNC so that kdbSet() knows which keys were modified
85 * After keyNew() the flag will normally be set, but after kdbGet()
86 * and kdbSet() the flag will be removed. When you modify the key
87 * the flag will be set again.
89 * In your application you can make use of that flag to know
90 * if you changed something in a key after a kdbGet() or kdbSet().
92 * @note Note that also changes in the meta data will set that flag.
95 * @param key the key object to work with
96 * @return 1 if @p key was changed in memory, 0 otherwise
97 * @return -1 on NULL pointer
100 int keyNeedSync(const Key *key)
104 return (key->flags & KEY_FLAG_SYNC) == KEY_FLAG_SYNC;
109 * Ask if key is marked for permanent remove.
111 * Ask if the key will be removed instead of writing in the key database
112 * when doing kdbSetKey() or kdbSet().
115 * @see kdbSet(), kdbSetKey(), kdbRemove()
116 * @param key the key object to work with
117 * @return 1 if it is marked, 0 otherwise
118 * @return -1 on NULL pointer
120 int keyNeedRemove(const Key *key)
124 return (key->flags & KEY_FLAG_REMOVE) == KEY_FLAG_REMOVE;
130 * Check whether a key is under the @p system namespace or not
132 * @param key the key object to work with
133 * @return 1 if key name begins with @p system, 0 otherwise
134 * @return -1 on NULL pointer
135 * @see keyIsUser(), keySetName(), keyName()
139 int keyIsSystem(const Key *key)
143 if (key->key) return keyNameIsSystem(key->key);
150 * Check whether a key is under the @p memory namespace or not
152 * @param key the key object to work with
153 * @return 1 if key name begins with @p system, 0 otherwise
154 * @return -1 on NULL pointer
155 * @see keyIsUser(), keySetName(), keyName()
159 int keyIsMemory(const Key *key)
163 if (key->key) return keyNameIsMemory(key->key);
170 * Check whether a key is under the @p user namespace or not.
172 * @param key the key object to work with
173 * @return 1 if key name begins with @p user, 0 otherwise
174 * @return -1 on NULL pointer
175 * @see keyIsSystem(), keySetName(), keyName()
179 int keyIsUser(const Key *key)
183 if (key->key) return keyNameIsUser(key->key);
190 * Check if the key check is below the key key or not.
195 check user/sw/app/key
197 returns true because check is below key
201 check user/sw/app/folder/key
203 returns also true because check is indirect below key
206 * @param key the key object to work with
207 * @param check the key to find the relative position of
208 * @return 1 if check is below key
209 * @return 0 if it is not below or if it is the same key
210 * @see keySetName(), keyGetName(), keyIsDirectBelow()
214 int keyIsBelow(const Key *key, const Key *check)
216 const char * keyname = 0;
217 const char * checkname = 0;
219 ssize_t checksize = 0;
221 if (!key || !check) return -1;
223 keyname = keyName(key);
224 checkname = keyName(check);
225 keysize = keyGetNameSize(key);
226 checksize = keyGetNameSize(check);
228 if (keysize > checksize + 1) return 0;
229 if (strncmp (keyname, checkname, keysize - 1)) return 0;
230 if (checkname[keysize - 1] != '/') return 0;
235 * Check if the key check is direct below the key key or not.
240 check user/sw/app/key
242 returns true because check is below key
246 check user/sw/app/folder/key
248 does not return true, because there is only a indirect relation
251 * @param key the key object to work with
252 * @param check the key to find the relative position of
253 * @return 1 if check is below key
254 * @return 0 if it is not below or if it is the same key
255 * @return -1 on null pointer
256 * @see keyIsBelow(), keySetName(), keyGetName()
260 int keyIsDirectBelow(const Key *key, const Key *check)
262 const char * checkname = 0;
265 if (!key || !check) return -1;
267 checkname = keyName(check);
268 keysize = keyGetNameSize(key);
270 if (!keyIsBelow(key, check)) return 0;
271 if (strchr(checkname + keysize, '/')) return 0;
277 * Check whether a key is inactive or not.
279 * In elektra terminology any key is inactive if the
280 * it's basename starts with '.'. Inactive keys
281 * must not have any meaning to applications, they
282 * are reserved for users and administrators.
284 * To remove a whole hierarchy in elektra, don't
285 * forget to pass option_t::KDB_O_INACTIVE to
286 * kdbGet() to receive the inactive keys in order
289 * Otherwise you should not fetch these keys.
291 * @param key the key object to work with
292 * @return 1 if the key is inactive, 0 otherwise
293 * @return -1 on NULL pointer or when key has no name
297 int keyIsInactive (const Key *key)
303 name = strrchr (keyName(key), '/');
305 if (!name) return -1;
307 /* the slash can't be a trailing slash
308 but there might be no name at all! */
309 if (name[1] == '.') return 1;
317 * Check if a key is directory key.
319 * Folder keys may also have value and comment.
320 * They are discern by having a executable bit
323 * If any executable bit is set it will be recognized
326 * @note keyIsDir may return true even though you
327 * can't access the directory.
329 * To know if you can access the directory, you
330 * need to check, if your
331 * - user ID is equal the key's
332 * user ID and the mode & 100 is true
333 * - group ID is equal the key's
334 * group ID and the mode & 010 is true
335 * - mode & 001 is true
337 * Accessing does not mean that you can get any value or
338 * comments below, see @ref mode for more information.
340 * @param key the key object to work with
341 * @return 1 if key is a directory, 0 otherwise
342 * @return -1 on NULL pointer
343 * @see keySetDir(), keySetMode()
346 int keyIsDir(const Key *key)
350 return ((key->mode & KEY_DEF_DIR) != 0);
355 * Check if a key is binary type.
357 * The function checks if the keytype is in the range between KEY_TYPE_BINARY and
358 * less than excluding KEY_TYPE_STRING. Then it will be interpreted as binary.
360 * Make sure to use this function and don't test the binary type another way to
361 * ensure compatibility and to write less error prone programs.
363 * @return 1 if it is binary
364 * @return 0 if it is not
365 * @return -1 on NULL pointer
366 * @see keySetType() for more information on types
367 * @see keyGetBinary(), keySetBinary()
368 * @param key the key to check
371 int keyIsBinary(const Key *key)
375 return (KEY_TYPE_BINARY <= key->type && key->type < KEY_TYPE_STRING);
380 * Check if a key is string type.
382 * The function checks if the keytype is larger or equal KEY_TYPE_STRING.
383 * Then it will be considered as string type.
385 * Make sure to use this function and don't test the string type another way to
386 * ensure compatibility and to write less error prone programs.
388 * @return 1 if it is string
389 * @return 0 if it is not
390 * @return -1 on NULL pointer
391 * @see keySetType for more information on types
392 * @see keyGetString(), keySetString()
393 * @param key the key to check
396 int keyIsString(const Key *key)
400 return (key->type >= KEY_TYPE_STRING);
410 * The returned flags bit array has 1s (differ) or 0s (equal) for each key
411 * meta info compared, that can be logically ORed using @c #keyswitch_t flags.
412 * The flags you can use are @link keyswitch_t::KEY_TYPE KEY_TYPE
413 * @endlink, @link keyswitch_t::KEY_NAME KEY_NAME @endlink,
414 * @link keyswitch_t::KEY_VALUE KEY_VALUE @endlink,
415 * @link keyswitch_t::KEY_OWNER KEY_OWNER @endlink,
416 * @link keyswitch_t::KEY_COMMENT KEY_COMMENT @endlink,
417 * @link keyswitch_t::KEY_UID KEY_UID @endlink,
418 * @link keyswitch_t::KEY_GID KEY_GID @endlink,
419 * @link keyswitch_t::KEY_MODE KEY_MODE @endlink and
421 * @par A very simple example would be
426 // omited key1 and key2 initialization and manipulation
428 changes=keyCompare(key1,key2);
430 if (changes == 0) printf("key1 and key2 are identicall\n");
432 if (changes & KEY_VALUE)
433 printf("key1 and key2 have different values\n");
435 if (changes & KEY_UID)
436 printf("key1 and key2 have different UID\n");
442 * @par Example of very powerfull specific Key lookup in a KeySet:
444 KDB *handle = kdbOpen();
446 Key *base = keyNew ("user/sw/MyApp/something", KEY_END);
452 kdbGetByName(handle, ks, "user/sw/MyApp", 0);
454 // we are interested only in key type and access permissions
455 interests=(KEY_TYPE | KEY_MODE);
457 ksRewind(ks); // put cursor in the begining
458 while ((curren=ksNext(ks))) {
459 match=keyCompare(current,base);
461 if ((~match & interests) == interests)
462 printf("Key %s has same type and permissions of base key",keyName(current));
464 // continue walking in the KeySet....
467 // now we want same name and/or value
468 interests=(KEY_NAME | KEY_VALUE);
470 // we don't really need ksRewind(), since previous loop achieved end of KeySet
472 while ((current=ksNext(ks))) {
473 match=keyCompare(current,base);
475 if ((~match & interests) == interests) {
476 printf("Key %s has same name, value, and sync status
477 of base key",keyName(current));
479 // continue walking in the KeySet....
487 * @return a bit array pointing the differences
488 * @param key1 first key
489 * @param key2 second key
493 keyswitch_t keyCompare(const Key *key1, const Key *key2)
496 const char *name1 = keyName(key1);
497 const char *name2 = keyName(key2);
498 const char *comment1 = keyComment(key1);
499 const char *comment2 = keyComment(key2);
500 const char *owner1 = keyOwner(key1);
501 const char *owner2 = keyOwner(key2);
502 const void *value1 = keyValue(key1);
503 const void *value2 = keyValue(key2);
504 int remove1 = keyNeedRemove(key1);
505 int remove2 = keyNeedRemove(key2);
506 ssize_t size1 = keyGetValueSize(key1);
507 ssize_t size2 = keyGetValueSize(key2);
510 if (key1->uid != key2->uid) ret|=KEY_UID;
511 if (key1->gid != key2->gid) ret|=KEY_GID;
512 if (key1->type != key2->type) ret|=KEY_TYPE;
513 if ((key1->mode) != (key2->mode)) ret|=KEY_MODE;
514 if (remove1 != remove2) ret|=KEY_REMOVE;
515 if (strcmp(name1, name2)) ret|=KEY_NAME;
516 if (strcmp(comment1, comment2)) ret|=KEY_COMMENT;
517 if (strcmp(owner1, owner2)) ret|=KEY_OWNER;
518 if (size1 != size2) ret|=KEY_VALUE;
519 if (memcmp(value1, value2, size1)) ret|=KEY_VALUE;