Functions | |
Plugin * | elektraPluginExport (const char *pluginName,...) |
KeySet * | elektraPluginGetConfig (Plugin *handle) |
void | elektraPluginSetData (Plugin *plugin, void *data) |
void * | elektraPluginGetData (Plugin *plugin) |
int | elektraDocOpen (Plugin *handle, Key *errorKey) |
int | elektraDocClose (Plugin *handle, Key *errorKey) |
int | elektraDocGet (Plugin *handle, KeySet *returned, Key *parentKey) |
int | elektraDocSet (Plugin *handle, KeySet *returned, Key *parentKey) |
Plugin * | ELEKTRA_PLUGIN_EXPORT (doc) |
A plugin can implement anything related to configuration. There are 5 possible entry points, but you need not to implement all of them. See the descriptions below what each of them is supposed to do.
Plugin* ELEKTRA_PLUGIN_EXPORT | ( | doc | ) |
All KDB methods implemented by the plugin can have random names, except kdbBackendFactory(). This is the single symbol that will be looked up when loading the plugin, and the first method of the backend implementation that will be called.
Its purpose is to publish the exported methods for libelektra.so. The implementation inside the provided skeleton is usually enough: simply call kdbBackendExport() with all methods that must be exported.
The first paramter is the name of the plugin. Then every plugin must have: KDB_BE_OPEN
, KDB_BE_CLOSE
, KDB_BE_GET
and KDB_BE_SET
You might also give following information by char *: KDB_BE_VERSION
, KDB_BE_AUTHOR
, KDB_BE_LICENCE
, KDB_BE_DESCRIPTION
, ELEKTRA_PLUGIN_NEEDS
and ELEKTRA_PLUGIN_PROVIDES
You must use static "char arrays" in a read only segment. Don't allocate storage, it won't be freed.
With capability you can get that information on runtime from any plugin with kdbGetCapability().
The last parameter must be KDB_BE_END
.
Finalize the plugin. Called prior to unloading the plugin dynamic module. Should ensure that no functions or static/global variables from the module will ever be accessed again.
Make sure to free all memory that your plugin requested at runtime.
Specifically make sure to capDel() all capabilites and free your pluginData in kdbhGetBackendData().
After this call, libelektra.so will unload the plugin library, so this is the point to shutdown any affairs with the storage.
handle | contains internal information of opened key database |
Retrieve information from a permanent storage to construct a keyset.
This function does everything related to get keys out from a plugin. There is only one function for that purpose to make implementation and locking much easier.
The keyset returned
needs to be filled with information so that the application using elektra can access it. See the live cycle of a comment to understand:
elektraDocGet(KDB *handle, KeySet *returned, Key *parentKey) { // the task of elektraPluginGet is to retrieve the comment out of the permanent storage Key *key = keyDup (parentKey); // generate a new key to hold the information char *comment; loadfromdisc (comment); keySetComment (key, comment, size); // set the information ksAppendKey(returned, key); } // Now return to kdbGet int elektraDocGet(Plugin *handle, KeySet *keyset, Key *parentKey) { elektraPluginGet (handle, keyset, 0); // postprocess the keyset and return it } // Now return to usercode, waiting for the comment void usercode (Key *key) { kdbGet (handle, keyset, parentKey, 0); key = ksCurrent (keyset, key); // lookup the key from the keyset keyGetComment (key); // now the usercode retrieves the comment }
Of course not only the comment, but all information of every key in the keyset returned
need to be fetched from permanent storage and stored in the key. So this specification needs to give an exhaustive list of information present in a key.
all
keys with the flag KEY_FLAG_SYNC set.returned
has the parentKey
and all keys direct below (keyIsDirectBelow()) with all information from the storage. Make sure to return all keys, all directories and also all hidden keys. If some of them are not wished, the caller kdbGet() will drop these keys, see above.Now lets look at an example how the typical elektraPluginGet() might be implemented. To explain we introduce some pseudo functions which do all the work with the storage (which is of course 90% of the work for a real plugin):
ssize_t elektraDocGet(KDB *handle, KeySet *update, const Key *parentKey) { Key * current; KeySet *returned = ksNew(ksGetSize(update)*2, KS_END); find_key (parentKey); current = keyDup (parentKey); current = fetch_key(current); keyClearSync (current); ksAppendKey(returned, current); while ((current = next_key()) != 0) { // search if key was passed in update by caller Key * tmp = ksLookup (update, current, KDB_O_WITHOWNER|KDB_O_POP); if (tmp) current = tmp; // key was passed, so use it current = fetch_key(current); keyClearSync (current); ksAppendKey(returned, current); // TODO: delete lookup key } if (error_happened()) { errno = restore_errno(); return -1; } ksClear (update); // the rest of update keys is not in storage anymore ksAppend(update, returned); // append the keys ksDel (returned); return nr_keys(); }
So your mission is simple: Search the parentKey
and add it and then search all keys below and add them too, of course with all the values.
To get all keys out of the storage over and over again can be very inefficient. You might know a more efficient method to know if the key needs update or not, e.g. by stating it or by an external time stamp info. In that case you can make use of returned
KeySet. There are following possibilities:
returned
keyset.In some plugins it is not useful to get only a part of the configuration, because getting all keys would take as long as getting some. For this situation, you can declare onlyFullGet, see kdbcGetonlyFullGet().
The only valid call for your plugin is then that parentKey
equals the mountpoint
. For all other parentKey
you must, add nothing and just return 0.
If the parentKey
is your mountpoint you will of course fetch all keys, and not only the keys direct below the parentKey
. So returned
is valid iff:
handle | contains internal information of opened key database | |
returned | contains a keyset where the function need to append the keys got from the storage. There might be also some keys inside it, see conditions. You may use them to support efficient updating of keys, see Updating. | |
parentKey | contains the information below which key the keys should be gotten. |
Initialize the plugin. This is the first method called after dynamically loading this plugin.
This method is responsible for:
You may also read the configuration you can get with elektraPluginGetConfig() and transform it into other structures used by your plugin.
Instead you can use elektraPluginGetData() and elektraPluginSetData() to store and get any information related to your plugin.
The correct substitute for global variables will be:
struct _GlobalData{ int global; }; typedef struct _GlobalData GlobalData; int elektraPluginOpen(KDB *handle) { PasswdData *data; data=malloc(sizeof(PasswdData)); data.global = 20; kdbhSetBackendData(handle,data); }
handle | contains internal information of opened key database | |
errorKey | defines an errorKey |
Store a keyset permanently.
This function does everything related to set and remove keys in a plugin. There is only one function for that purpose to make implementation and locking much easier.
The keyset returned
was filled in with information from the application using elektra and the task of this function is to store it in a permanent way so that a subsequent call of elektraPluginGet() can rebuild the keyset as it was before. See the live cycle of a comment to understand:
void usercode (Key *key) { keySetComment (key, "mycomment"); // the usercode stores a comment for the key ksAppendKey(keyset, key); // append the key to the keyset kdbSet (handle, keyset, 0, 0); } // so now kdbSet is called int kdbSet(KDB *handle, KeySet *keyset, Key *parentKey, options) { // find appropriate plugin elektraPluginSet (handle, keyset, 0); // the keyset with the key will be passed to this function } // so now elektraPluginSet(), which is the function described here, is called elektraPluginSet(KDB *handle, KeySet *keyset, Key *parentKey) { // the task of elektraPluginSet is now to store the comment Key *key = ksCurrent (keyset); // get out the key where the user set the comment before char *comment = allocate(size); keyGetComment (key, comment, size); savetodisc (comment); }
Of course not only the comment, but all information of every key in the keyset returned
need to be stored permanetly. So this specification needs to give an exhaustive list of information present in a key.
returned
holds all keys which must be saved permanently for this keyset. The keyset is sorted and rewinded. All keys having children must be true for keyIsDir().parentKey
is the key which is the ancestor for all other keys in the keyset. The first key of the keyset returned
has the same keyname. The parentKey is below the mountpoint, see kdbhGetMountpoint().returned
need to be stored permanently.returned
is stored permanently.Lock your permanent storage in an exclusive way, no access of a concurrent elektraPluginSet_plugin() or kdbGet() is possible and these methods block until the function has finished. Otherwise declare kdbcGetnoLock().
handle | contains internal information of opened key database | |
returned | contains a keyset with relevant keys | |
parentKey | contains the information where to set the keys |
You also have to make sure that ksGetCursor() shows to the position where the error appeared.
Plugin* elektraPluginExport | ( | const char * | pluginName, | |
... | ||||
) |
This function must be called by a plugin's elektraPluginSymbol() to define the plugin's methods that will be exported.
See ELEKTRA_PLUGIN_EXPORT() how to use it for plugins.
The order and number of arguments are flexible (as in keyNew() and ksNew()) to let libelektra.so evolve without breaking its ABI compatibility with plugins. So for each method a plugin must export, there is a flag defined by plugin_t. Each flag tells kdbPluginExport() which method comes next. A plugin can have no implementation for a few methods that have default inefficient high-level implementations and to use these defaults, simply don't pass anything to kdbPluginExport() about them.
pluginName | a simple name for this plugin |
Returns the configuration of that plugin.
handle | a pointer to the plugin |
void* elektraPluginGetData | ( | Plugin * | plugin | ) |
Get a pointer to any plugin related data stored before.
plugin | a pointer to the plugin |
void elektraPluginSetData | ( | Plugin * | plugin, | |
void * | data | |||
) |
Store a pointer to any plugin related data.
plugin | a pointer to the plugin | |
data | the pointer to the data |