From 4db9d9f6f3683d1b44284508dce975205937d108 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Sun, 18 Sep 2022 19:53:27 +0200 Subject: [PATCH 01/38] hooks: very basic implementation for gopts hook --- src/include/kdbprivate.h | 19 ++++++- src/libs/elektra/CMakeLists.txt | 1 + src/libs/elektra/hooks.c | 96 +++++++++++++++++++++++++++++++++ src/libs/elektra/kdb.c | 34 +++++++++++- src/libs/elektra/plugin.c | 2 +- src/plugins/gopts/gopts.c | 1 + 6 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 src/libs/elektra/hooks.c diff --git a/src/include/kdbprivate.h b/src/include/kdbprivate.h index 4731401d252..766ebf61ea1 100644 --- a/src/include/kdbprivate.h +++ b/src/include/kdbprivate.h @@ -99,6 +99,8 @@ typedef int (*kdbSetPtr) (Plugin * handle, KeySet * returned, Key * parentKey); typedef int (*kdbErrorPtr) (Plugin * handle, KeySet * returned, Key * parentKey); typedef int (*kdbCommitPtr) (Plugin * handle, KeySet * returned, Key * parentKey); +typedef int (*kdbHookGoptsGetPtr) (Plugin * handle, KeySet * returned, Key * parentKey); + typedef Plugin * (*OpenMapper) (const char *, const char *, KeySet *); typedef int (*CloseMapper) (Plugin *); @@ -319,6 +321,7 @@ struct _KeySet #endif }; +typedef struct _Hooks Hooks; /** * The access point to the key database. @@ -362,7 +365,7 @@ struct _KDB up their parts of the global keyset, which they do not need any more.*/ Plugin * globalPlugins[NR_GLOBAL_POSITIONS][NR_GLOBAL_SUBPOSITIONS]; - + Hooks * hooks; KeySet * backends; }; @@ -411,6 +414,18 @@ struct _Plugin KeySet * modules; /*!< A list of all currently loaded modules.*/ }; +struct _HookPluginGopts +{ + struct _Plugin* plugin; + kdbHookGoptsGetPtr kdbHookGoptsGet; +}; + +struct _Hooks +{ + struct _HookPluginGopts* gopts; + bool goptsEnabled; +}; + // FIXME (kodebach): document typedef struct _BackendData { @@ -564,6 +579,8 @@ int mountModules (KDB * kdb, KeySet * modules, Key * errorKey); int mountVersion (KDB * kdb, Key * errorKey); int mountGlobals (KDB * kdb, KeySet * keys, KeySet * modules, Key * errorKey); int mountBackend (KDB * kdb, const Key * mountpoint, Plugin * backend); +int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey); +void freeHooks(KDB * kdb, Key * errorKey); const Key * mountGetMountpoint (KDB * handle, Key * where); Plugin * mountGetBackend (KDB * handle, Key * key); diff --git a/src/libs/elektra/CMakeLists.txt b/src/libs/elektra/CMakeLists.txt index 158deab1b27..d10f27ff886 100644 --- a/src/libs/elektra/CMakeLists.txt +++ b/src/libs/elektra/CMakeLists.txt @@ -63,6 +63,7 @@ if (BUILD_SHARED) backend.c kdb.c mount.c + hooks.c split.c trie.c plugin.c diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c new file mode 100644 index 00000000000..7a86dd935c3 --- /dev/null +++ b/src/libs/elektra/hooks.c @@ -0,0 +1,96 @@ +/** +* @file +* +* @brief +* +* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) +*/ + +#include + +void freeHooks(KDB * kdb, Key * errorKey) +{ + if(kdb->hooks == NULL) + { + return; + } + + if(kdb->hooks->gopts != NULL) + { + elektraPluginClose (kdb->hooks->gopts->plugin, errorKey); + free(kdb->hooks->gopts); + kdb->hooks->gopts = NULL; + } + + free(kdb->hooks); + kdb->hooks = NULL; +} + +static struct _HookPluginGopts * initHooksGopts (Plugin * plugin) +{ + if(!plugin) + { + return NULL; + } + + struct _HookPluginGopts * hook = elektraCalloc (sizeof(struct _HookPluginGopts)); + hook->plugin = plugin; + + hook->kdbHookGoptsGet = (kdbHookGoptsGetPtr) elektraPluginGetFunction(plugin, "hooks/gopts/get"); + return hook; +} + +static Plugin * loadPlugin(const char * pluginName, KeySet * config, KeySet * modules, Key * errorKey) +{ + Key* openKey = keyDup (errorKey, KEY_CP_ALL); + + Plugin * plugin = elektraPluginOpen (pluginName, modules, config, openKey); + + if (!plugin) + { + ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Could not load plugin '%s'", pluginName); + keyCopyAllMeta (errorKey, openKey); + keyDel (openKey); + return NULL; + } + + return plugin; +} + +static bool isGoptsEnabledByContract(KDB * kdb) +{ + bool goptsEnabled = false; + + KeySet * ksTemp = ksDup (kdb->global); + Key * cutPoint = keyNew ("system:/elektra/gopts", KEY_END); + + KeySet * cut = ksCut (ksTemp, cutPoint); + + goptsEnabled = ksGetSize (cut) > 0; + + keyDel (cutPoint); + ksDel(ksTemp); + ksDel (cut); + + return goptsEnabled; +} + +int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey) +{ + freeHooks (kdb, errorKey); + kdb->hooks = elektraCalloc (sizeof (Hooks)); + + if(isGoptsEnabledByContract (kdb)) + { + kdb->hooks->gopts = initHooksGopts (loadPlugin ("gopts", config, modules, errorKey)); + kdb->hooks->goptsEnabled = kdb->hooks->gopts != NULL; + + if(kdb->hooks->gopts == NULL) + { + ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); + } + } + + return 0; +} + diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 63f67f0eddb..893322556ee 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -378,6 +378,7 @@ static KDB * kdbNew (Key * errorKey) handle->global = ksNew (1, keyNew ("system:/elektra/kdb", KEY_BINARY, KEY_SIZE, sizeof (handle), KEY_VALUE, &handle, KEY_END), KS_END); handle->backends = ksNew (0, KS_END); + handle->hooks = elektraCalloc (sizeof (struct _Hooks)); return handle; } @@ -1006,6 +1007,14 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) goto error; } + // TOOD (atmaxinger): improve + if(initHooks (handle, ksDup (elektraKs), handle->modules, errorKey) == -1) + { + ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Mounting hooks failed. Please see warning of concrete plugin"); + ksDel (elektraKs); + goto error; + } + // Step 6: parse mountpoints KeySet * backends = elektraMountpointsParse (elektraKs, handle->modules, handle->global, errorKey); if (backends == NULL) @@ -1120,6 +1129,11 @@ int kdbClose (KDB * handle, Key * errorKey) } } + if(handle->hooks) + { + freeHooks (handle, errorKey); + } + if (handle->modules) { elektraModulesClose (handle->modules, errorKey); @@ -1736,7 +1750,8 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) #endif // Step 1: find backends for parentKey KeySet * backends = backendsForParentKey (handle->backends, parentKey); - bool goptsActive = handle->globalPlugins[PROCGETSTORAGE][MAXONCE] != NULL; + + bool goptsActive = handle->hooks->goptsEnabled; // handle->globalPlugins[PROCGETSTORAGE][MAXONCE] != NULL; if (goptsActive) { // HACK: for gopts; generates keys outside backend @@ -1874,6 +1889,23 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); */ + // Step 13: run gopts (if enabled) + keyCopy (parentKey, initialParent, KEY_CP_NAME); + /*keySetNamespace (cascadingParent, KEY_NS_CASCADING); + set_bit (parentKey, KEY_LOCK_NAME | KEY_LOCK_VALUE); + if (goptsActive && !goptsGet (dataKs, cascadingParent)) + { + clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); + goto error; + }*/ + + if(goptsActive && !handle->hooks->gopts->kdbHookGoptsGet (handle->hooks->gopts->plugin, dataKs, parentKey)) + { + clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); + goto error; + } + + // Step 15: split dataKs for poststorage phase // FIXME (kodebach): handle proc:/ keys if (!backendsDivide (backends, dataKs)) diff --git a/src/libs/elektra/plugin.c b/src/libs/elektra/plugin.c index 31864ed72e8..f861dc0e391 100644 --- a/src/libs/elektra/plugin.c +++ b/src/libs/elektra/plugin.c @@ -167,7 +167,7 @@ size_t elektraPluginGetFunction (Plugin * plugin, const char * name) plugin->kdbGet (plugin, exports, pk); ksRewind (exports); keyAddBaseName (pk, "exports"); - keyAddBaseName (pk, name); + keyAddName (pk, name); // we may not want to escape for hooks exports Key * keyFunction = ksLookup (exports, pk, 0); if (!keyFunction) { diff --git a/src/plugins/gopts/gopts.c b/src/plugins/gopts/gopts.c index f57cda39ddf..e867c0e5956 100644 --- a/src/plugins/gopts/gopts.c +++ b/src/plugins/gopts/gopts.c @@ -43,6 +43,7 @@ int elektraGOptsGet (Plugin * handle, KeySet * returned, Key * parentKey) ksNew (30, keyNew ("system:/elektra/modules/gopts", KEY_VALUE, "gopts plugin waits for your orders", KEY_END), keyNew ("system:/elektra/modules/gopts/exports", KEY_END), keyNew ("system:/elektra/modules/gopts/exports/get", KEY_FUNC, elektraGOptsGet, KEY_END), + keyNew ("system:/elektra/modules/gopts/exports/hooks/gopts/get", KEY_FUNC, elektraGOptsGet, KEY_END), #include ELEKTRA_README keyNew ("system:/elektra/modules/gopts/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END); ksAppend (returned, contract); From c46dd8bd36670f35ee8d298f4d4eb6916e15fd70 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Sun, 18 Sep 2022 21:31:59 +0200 Subject: [PATCH 02/38] hooks: start with some basic development documentation --- doc/dev/hooks.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 doc/dev/hooks.md diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md new file mode 100644 index 00000000000..d6a9c145bda --- /dev/null +++ b/doc/dev/hooks.md @@ -0,0 +1,24 @@ +# Hooks + +Hooks are central points in the KDB lifecycle, where specialized plugins are called. +Hooks are the new mechanism that will replace the old global plugins, [as specified in this decision](../decisions/global_plugins.md). + +## Selecting which Plugin will be used for a specific hook + +Currently, the names of the plugins are hard-coded. + +## Interface of the hooks + +If a plugin should be able to act upon a hook, it must export all the functions that the hook requires. +These exports are of the form `system:/elektra/modules//exports/hooks//`. + +For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefor has to export `system:/elektra/modules//exports/hooks/gopts/get`. + +Other hooks might require multiple exported functions. + +## Lifecycle + +1. Hooks are initilized within `kdbOpen` after the contract has been processed. This includes loading the plugins. +2. The appropriate hooks are called within each `kdbGet` and `kdbSet` call. +3. Hooks are deinitialized within `kdbClose`. This includes unloading the plugins. + From 46d5ea491d634eeec4c24668442727f33bfd139e Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 18 Sep 2022 19:36:42 +0000 Subject: [PATCH 03/38] Restyled by clang-format --- src/include/kdbprivate.h | 2 +- src/libs/elektra/hooks.c | 41 ++++++++++++++++++++-------------------- src/libs/elektra/kdb.c | 6 +++--- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/include/kdbprivate.h b/src/include/kdbprivate.h index 766ebf61ea1..2803931d65d 100644 --- a/src/include/kdbprivate.h +++ b/src/include/kdbprivate.h @@ -580,7 +580,7 @@ int mountVersion (KDB * kdb, Key * errorKey); int mountGlobals (KDB * kdb, KeySet * keys, KeySet * modules, Key * errorKey); int mountBackend (KDB * kdb, const Key * mountpoint, Plugin * backend); int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey); -void freeHooks(KDB * kdb, Key * errorKey); +void freeHooks (KDB * kdb, Key * errorKey); const Key * mountGetMountpoint (KDB * handle, Key * where); Plugin * mountGetBackend (KDB * handle, Key * key); diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 7a86dd935c3..36f954ad5d9 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -1,48 +1,48 @@ /** -* @file -* -* @brief -* -* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) -*/ + * @file + * + * @brief + * + * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) + */ #include -void freeHooks(KDB * kdb, Key * errorKey) +void freeHooks (KDB * kdb, Key * errorKey) { - if(kdb->hooks == NULL) + if (kdb->hooks == NULL) { return; } - if(kdb->hooks->gopts != NULL) + if (kdb->hooks->gopts != NULL) { elektraPluginClose (kdb->hooks->gopts->plugin, errorKey); - free(kdb->hooks->gopts); + free (kdb->hooks->gopts); kdb->hooks->gopts = NULL; } - free(kdb->hooks); + free (kdb->hooks); kdb->hooks = NULL; } static struct _HookPluginGopts * initHooksGopts (Plugin * plugin) { - if(!plugin) + if (!plugin) { return NULL; } - struct _HookPluginGopts * hook = elektraCalloc (sizeof(struct _HookPluginGopts)); + struct _HookPluginGopts * hook = elektraCalloc (sizeof (struct _HookPluginGopts)); hook->plugin = plugin; - hook->kdbHookGoptsGet = (kdbHookGoptsGetPtr) elektraPluginGetFunction(plugin, "hooks/gopts/get"); + hook->kdbHookGoptsGet = (kdbHookGoptsGetPtr) elektraPluginGetFunction (plugin, "hooks/gopts/get"); return hook; } -static Plugin * loadPlugin(const char * pluginName, KeySet * config, KeySet * modules, Key * errorKey) +static Plugin * loadPlugin (const char * pluginName, KeySet * config, KeySet * modules, Key * errorKey) { - Key* openKey = keyDup (errorKey, KEY_CP_ALL); + Key * openKey = keyDup (errorKey, KEY_CP_ALL); Plugin * plugin = elektraPluginOpen (pluginName, modules, config, openKey); @@ -57,7 +57,7 @@ static Plugin * loadPlugin(const char * pluginName, KeySet * config, KeySet * mo return plugin; } -static bool isGoptsEnabledByContract(KDB * kdb) +static bool isGoptsEnabledByContract (KDB * kdb) { bool goptsEnabled = false; @@ -69,7 +69,7 @@ static bool isGoptsEnabledByContract(KDB * kdb) goptsEnabled = ksGetSize (cut) > 0; keyDel (cutPoint); - ksDel(ksTemp); + ksDel (ksTemp); ksDel (cut); return goptsEnabled; @@ -80,12 +80,12 @@ int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey) freeHooks (kdb, errorKey); kdb->hooks = elektraCalloc (sizeof (Hooks)); - if(isGoptsEnabledByContract (kdb)) + if (isGoptsEnabledByContract (kdb)) { kdb->hooks->gopts = initHooksGopts (loadPlugin ("gopts", config, modules, errorKey)); kdb->hooks->goptsEnabled = kdb->hooks->gopts != NULL; - if(kdb->hooks->gopts == NULL) + if (kdb->hooks->gopts == NULL) { ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); } @@ -93,4 +93,3 @@ int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey) return 0; } - diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 893322556ee..73cf734091a 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1008,7 +1008,7 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) } // TOOD (atmaxinger): improve - if(initHooks (handle, ksDup (elektraKs), handle->modules, errorKey) == -1) + if (initHooks (handle, ksDup (elektraKs), handle->modules, errorKey) == -1) { ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Mounting hooks failed. Please see warning of concrete plugin"); ksDel (elektraKs); @@ -1129,7 +1129,7 @@ int kdbClose (KDB * handle, Key * errorKey) } } - if(handle->hooks) + if (handle->hooks) { freeHooks (handle, errorKey); } @@ -1899,7 +1899,7 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) goto error; }*/ - if(goptsActive && !handle->hooks->gopts->kdbHookGoptsGet (handle->hooks->gopts->plugin, dataKs, parentKey)) + if (goptsActive && !handle->hooks->gopts->kdbHookGoptsGet (handle->hooks->gopts->plugin, dataKs, parentKey)) { clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); goto error; From 6dc6bb8305ff8d9581f2ffa518d9120045f21eae Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 18 Sep 2022 19:36:52 +0000 Subject: [PATCH 04/38] Restyled by prettier-markdown --- doc/dev/hooks.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index d6a9c145bda..7b683f65137 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -1,6 +1,6 @@ # Hooks -Hooks are central points in the KDB lifecycle, where specialized plugins are called. +Hooks are central points in the KDB lifecycle, where specialized plugins are called. Hooks are the new mechanism that will replace the old global plugins, [as specified in this decision](../decisions/global_plugins.md). ## Selecting which Plugin will be used for a specific hook @@ -21,4 +21,3 @@ Other hooks might require multiple exported functions. 1. Hooks are initilized within `kdbOpen` after the contract has been processed. This includes loading the plugins. 2. The appropriate hooks are called within each `kdbGet` and `kdbSet` call. 3. Hooks are deinitialized within `kdbClose`. This includes unloading the plugins. - From fb88bafedc63b5b2cecd4aa147d6b591bec72ac6 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:20:29 +0200 Subject: [PATCH 05/38] Update doc/dev/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/dev/hooks.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index 7b683f65137..66b9d5edc83 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -6,6 +6,8 @@ Hooks are the new mechanism that will replace the old global plugins, [as specif ## Selecting which Plugin will be used for a specific hook Currently, the names of the plugins are hard-coded. +This decision was made, because these plugins are meant to fulfil very specific purposes. +A symlink replacing the shared library file of the plugin could be used to change the implementation. ## Interface of the hooks From 23dc73d4f8988e4408628046035f397955aca916 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:20:36 +0200 Subject: [PATCH 06/38] Update doc/dev/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/dev/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index 66b9d5edc83..bcf99bb3c29 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -14,7 +14,7 @@ A symlink replacing the shared library file of the plugin could be used to chang If a plugin should be able to act upon a hook, it must export all the functions that the hook requires. These exports are of the form `system:/elektra/modules//exports/hooks//`. -For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefor has to export `system:/elektra/modules//exports/hooks/gopts/get`. +For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefore has to export `system:/elektra/modules//exports/hooks/gopts/get`. Other hooks might require multiple exported functions. From 4337199c86c4cdcdf5525e4abd57f410b4e2dfdf Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:20:50 +0200 Subject: [PATCH 07/38] Update doc/dev/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/dev/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index bcf99bb3c29..7f9430ce55a 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -16,7 +16,7 @@ These exports are of the form `system:/elektra/modules//exports/hoo For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefore has to export `system:/elektra/modules//exports/hooks/gopts/get`. -Other hooks might require multiple exported functions. +Other hooks (e.g. `spec`) might require multiple exported functions. ## Lifecycle From e21b0cecaa4fe807dc099827fe31227dd8c9ad5d Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:20:59 +0200 Subject: [PATCH 08/38] Update doc/dev/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/dev/hooks.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index 7f9430ce55a..e419a716dce 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -1,7 +1,6 @@ # Hooks Hooks are central points in the KDB lifecycle, where specialized plugins are called. -Hooks are the new mechanism that will replace the old global plugins, [as specified in this decision](../decisions/global_plugins.md). ## Selecting which Plugin will be used for a specific hook From f540ac319b42d5c0a16a5883ab6d954d79509607 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:26:40 +0200 Subject: [PATCH 09/38] Update src/libs/elektra/kdb.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- src/libs/elektra/kdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 73cf734091a..9fc47666281 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1891,6 +1891,7 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) // Step 13: run gopts (if enabled) keyCopy (parentKey, initialParent, KEY_CP_NAME); + keySetNamespace (parentKey, KEY_NS_CASCADING); /*keySetNamespace (cascadingParent, KEY_NS_CASCADING); set_bit (parentKey, KEY_LOCK_NAME | KEY_LOCK_VALUE); if (goptsActive && !goptsGet (dataKs, cascadingParent)) From b9d1993f90daf36f1feb94cb32944208b7f70af8 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:49:29 +0200 Subject: [PATCH 10/38] hooks: change to inline struct --- src/include/kdbprivate.h | 22 +++++++++------------- src/libs/elektra/hooks.c | 36 +++++++++--------------------------- src/libs/elektra/kdb.c | 29 ++++------------------------- 3 files changed, 22 insertions(+), 65 deletions(-) diff --git a/src/include/kdbprivate.h b/src/include/kdbprivate.h index 2803931d65d..5e8308d7f80 100644 --- a/src/include/kdbprivate.h +++ b/src/include/kdbprivate.h @@ -365,8 +365,16 @@ struct _KDB up their parts of the global keyset, which they do not need any more.*/ Plugin * globalPlugins[NR_GLOBAL_POSITIONS][NR_GLOBAL_SUBPOSITIONS]; - Hooks * hooks; KeySet * backends; + + struct + { + struct + { + struct _Plugin* plugin; + kdbHookGoptsGetPtr kdbHookGoptsGet; + } gopts; + } hooks; }; /** @@ -414,18 +422,6 @@ struct _Plugin KeySet * modules; /*!< A list of all currently loaded modules.*/ }; -struct _HookPluginGopts -{ - struct _Plugin* plugin; - kdbHookGoptsGetPtr kdbHookGoptsGet; -}; - -struct _Hooks -{ - struct _HookPluginGopts* gopts; - bool goptsEnabled; -}; - // FIXME (kodebach): document typedef struct _BackendData { diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 36f954ad5d9..2d247c4b7c5 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -10,34 +10,23 @@ void freeHooks (KDB * kdb, Key * errorKey) { - if (kdb->hooks == NULL) + if (kdb->hooks.gopts.plugin != NULL) { - return; + elektraPluginClose (kdb->hooks.gopts.plugin, errorKey); } - - if (kdb->hooks->gopts != NULL) - { - elektraPluginClose (kdb->hooks->gopts->plugin, errorKey); - free (kdb->hooks->gopts); - kdb->hooks->gopts = NULL; - } - - free (kdb->hooks); - kdb->hooks = NULL; } -static struct _HookPluginGopts * initHooksGopts (Plugin * plugin) +static int initHooksGopts (KDB * kdb, Plugin * plugin) { if (!plugin) { - return NULL; + return -1; } - struct _HookPluginGopts * hook = elektraCalloc (sizeof (struct _HookPluginGopts)); - hook->plugin = plugin; + kdb->hooks.gopts.plugin = plugin; + kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) elektraPluginGetFunction (plugin, "hooks/gopts/get"); - hook->kdbHookGoptsGet = (kdbHookGoptsGetPtr) elektraPluginGetFunction (plugin, "hooks/gopts/get"); - return hook; + return 0; } static Plugin * loadPlugin (const char * pluginName, KeySet * config, KeySet * modules, Key * errorKey) @@ -78,17 +67,10 @@ static bool isGoptsEnabledByContract (KDB * kdb) int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey) { freeHooks (kdb, errorKey); - kdb->hooks = elektraCalloc (sizeof (Hooks)); - if (isGoptsEnabledByContract (kdb)) + if (isGoptsEnabledByContract (kdb) && !initHooksGopts (kdb, loadPlugin ("gopts", config, modules, errorKey))) { - kdb->hooks->gopts = initHooksGopts (loadPlugin ("gopts", config, modules, errorKey)); - kdb->hooks->goptsEnabled = kdb->hooks->gopts != NULL; - - if (kdb->hooks->gopts == NULL) - { - ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); - } + ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); } return 0; diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 9fc47666281..0ef343dc449 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -378,7 +378,6 @@ static KDB * kdbNew (Key * errorKey) handle->global = ksNew (1, keyNew ("system:/elektra/kdb", KEY_BINARY, KEY_SIZE, sizeof (handle), KEY_VALUE, &handle, KEY_END), KS_END); handle->backends = ksNew (0, KS_END); - handle->hooks = elektraCalloc (sizeof (struct _Hooks)); return handle; } @@ -1129,10 +1128,7 @@ int kdbClose (KDB * handle, Key * errorKey) } } - if (handle->hooks) - { - freeHooks (handle, errorKey); - } + freeHooks (handle, errorKey); if (handle->modules) { @@ -1751,7 +1747,7 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) // Step 1: find backends for parentKey KeySet * backends = backendsForParentKey (handle->backends, parentKey); - bool goptsActive = handle->hooks->goptsEnabled; // handle->globalPlugins[PROCGETSTORAGE][MAXONCE] != NULL; + bool goptsActive = handle->hooks.gopts.plugin != NULL; if (goptsActive) { // HACK: for gopts; generates keys outside backend @@ -1869,17 +1865,6 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) } /* TODO (kodebach): implement actual steps with new global plugins - // Step 13: run gopts (if enabled) - keyCopy (parentKey, initialParent, KEY_CP_NAME); - keySetNamespace (cascadingParent, KEY_NS_CASCADING); - set_bit (parentKey, KEY_LOCK_NAME | KEY_LOCK_VALUE); - bool goptsEnabled = false; - if (goptsEnabled && !goptsGet (dataKs, cascadingParent)) - { - clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); - goto error; - } - // Step 14: run spec plugin if (!specGet (dataKs, cascadingParent)) { @@ -1892,20 +1877,14 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) // Step 13: run gopts (if enabled) keyCopy (parentKey, initialParent, KEY_CP_NAME); keySetNamespace (parentKey, KEY_NS_CASCADING); - /*keySetNamespace (cascadingParent, KEY_NS_CASCADING); - set_bit (parentKey, KEY_LOCK_NAME | KEY_LOCK_VALUE); - if (goptsActive && !goptsGet (dataKs, cascadingParent)) - { - clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); - goto error; - }*/ - if (goptsActive && !handle->hooks->gopts->kdbHookGoptsGet (handle->hooks->gopts->plugin, dataKs, parentKey)) + if (goptsActive && !handle->hooks.gopts.kdbHookGoptsGet (handle->hooks.gopts.plugin, dataKs, parentKey)) { clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE); goto error; } + keySetNamespace (parentKey, keyGetNamespace (initialParent)); // Step 15: split dataKs for poststorage phase // FIXME (kodebach): handle proc:/ keys From eb5cb13bc1f270592fade406391380eca57bb24e Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 08:53:37 +0200 Subject: [PATCH 11/38] hooks: initHooks now takes contract --- src/include/kdbprivate.h | 2 +- src/libs/elektra/hooks.c | 23 +++++++---------------- src/libs/elektra/kdb.c | 10 +++++----- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/include/kdbprivate.h b/src/include/kdbprivate.h index 5e8308d7f80..57d312609a6 100644 --- a/src/include/kdbprivate.h +++ b/src/include/kdbprivate.h @@ -575,7 +575,7 @@ int mountModules (KDB * kdb, KeySet * modules, Key * errorKey); int mountVersion (KDB * kdb, Key * errorKey); int mountGlobals (KDB * kdb, KeySet * keys, KeySet * modules, Key * errorKey); int mountBackend (KDB * kdb, const Key * mountpoint, Plugin * backend); -int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey); +int initHooks (KDB * kdb, KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey); void freeHooks (KDB * kdb, Key * errorKey); const Key * mountGetMountpoint (KDB * handle, Key * where); diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 2d247c4b7c5..0fcc469f75c 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -46,29 +46,20 @@ static Plugin * loadPlugin (const char * pluginName, KeySet * config, KeySet * m return plugin; } -static bool isGoptsEnabledByContract (KDB * kdb) +static bool isGoptsEnabledByContract (const KeySet * contract) { - bool goptsEnabled = false; + KeySet * dupContract = ksDup (contract); // We need to duplicate because contract is const, and ksLookupByName doesn't take const + bool isEnabled = ksLookupByName (dupContract, "system:/elektra/contract/mountglobal/gopts", 0) != NULL; + ksDel (dupContract); - KeySet * ksTemp = ksDup (kdb->global); - Key * cutPoint = keyNew ("system:/elektra/gopts", KEY_END); - - KeySet * cut = ksCut (ksTemp, cutPoint); - - goptsEnabled = ksGetSize (cut) > 0; - - keyDel (cutPoint); - ksDel (ksTemp); - ksDel (cut); - - return goptsEnabled; + return isEnabled; } -int initHooks (KDB * kdb, KeySet * config, KeySet * modules, Key * errorKey) +int initHooks (KDB * kdb, KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey) { freeHooks (kdb, errorKey); - if (isGoptsEnabledByContract (kdb) && !initHooksGopts (kdb, loadPlugin ("gopts", config, modules, errorKey))) + if (isGoptsEnabledByContract (contract) && !initHooksGopts (kdb, loadPlugin ("gopts", config, modules, errorKey))) { ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); } diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 0ef343dc449..2b417baf214 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -999,17 +999,17 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) goto error; } - // Step 5: process contract - if (contract != NULL && !ensureContract (handle, contract, errorKey)) + // TODO (atmaxinger): improve + if (initHooks (handle, ksDup (elektraKs), handle->modules, contract, errorKey) == -1) { + ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Mounting hooks failed. Please see warning of concrete plugin"); ksDel (elektraKs); goto error; } - // TOOD (atmaxinger): improve - if (initHooks (handle, ksDup (elektraKs), handle->modules, errorKey) == -1) + // Step 5: process contract + if (contract != NULL && !ensureContract (handle, contract, errorKey)) { - ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Mounting hooks failed. Please see warning of concrete plugin"); ksDel (elektraKs); goto error; } From 4b43a71751028404206f463583b240f49b58e246 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 09:05:17 +0200 Subject: [PATCH 12/38] hooks: pass empty keyset as plugin config --- src/include/kdbprivate.h | 2 +- src/libs/elektra/hooks.c | 8 ++++---- src/libs/elektra/kdb.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/include/kdbprivate.h b/src/include/kdbprivate.h index 57d312609a6..bdc6dcf133b 100644 --- a/src/include/kdbprivate.h +++ b/src/include/kdbprivate.h @@ -575,7 +575,7 @@ int mountModules (KDB * kdb, KeySet * modules, Key * errorKey); int mountVersion (KDB * kdb, Key * errorKey); int mountGlobals (KDB * kdb, KeySet * keys, KeySet * modules, Key * errorKey); int mountBackend (KDB * kdb, const Key * mountpoint, Plugin * backend); -int initHooks (KDB * kdb, KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey); +int initHooks (KDB * kdb, KeySet * modules, const KeySet * contract, Key * errorKey); void freeHooks (KDB * kdb, Key * errorKey); const Key * mountGetMountpoint (KDB * handle, Key * where); diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 0fcc469f75c..50c9e803ede 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -29,11 +29,11 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin) return 0; } -static Plugin * loadPlugin (const char * pluginName, KeySet * config, KeySet * modules, Key * errorKey) +static Plugin * loadPlugin (const char * pluginName,KeySet * modules, Key * errorKey) { Key * openKey = keyDup (errorKey, KEY_CP_ALL); - Plugin * plugin = elektraPluginOpen (pluginName, modules, config, openKey); + Plugin * plugin = elektraPluginOpen (pluginName, modules, ksNew (0, KS_END), openKey); if (!plugin) { @@ -55,11 +55,11 @@ static bool isGoptsEnabledByContract (const KeySet * contract) return isEnabled; } -int initHooks (KDB * kdb, KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey) +int initHooks (KDB * kdb, KeySet * modules, const KeySet * contract, Key * errorKey) { freeHooks (kdb, errorKey); - if (isGoptsEnabledByContract (contract) && !initHooksGopts (kdb, loadPlugin ("gopts", config, modules, errorKey))) + if (isGoptsEnabledByContract (contract) && !initHooksGopts (kdb, loadPlugin ("gopts", modules, errorKey))) { ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); } diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 2b417baf214..cd218b44b68 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1000,7 +1000,7 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) } // TODO (atmaxinger): improve - if (initHooks (handle, ksDup (elektraKs), handle->modules, contract, errorKey) == -1) + if (initHooks (handle, handle->modules, contract, errorKey) == -1) { ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Mounting hooks failed. Please see warning of concrete plugin"); ksDel (elektraKs); From a909c64e176d215e5ca1e2e7c3aed2bc5ad39f99 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 19 Sep 2022 07:05:29 +0000 Subject: [PATCH 13/38] Restyled by clang-format --- src/libs/elektra/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 50c9e803ede..ac724dc26ad 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -29,7 +29,7 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin) return 0; } -static Plugin * loadPlugin (const char * pluginName,KeySet * modules, Key * errorKey) +static Plugin * loadPlugin (const char * pluginName, KeySet * modules, Key * errorKey) { Key * openKey = keyDup (errorKey, KEY_CP_ALL); From 52e753012786e7ec6ea8e8c4a79581bcb6dbdc98 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 09:29:21 +0200 Subject: [PATCH 14/38] hooks: better error handling when initializing --- src/libs/elektra/hooks.c | 28 ++++++++++++++++++++++++---- src/libs/elektra/kdb.c | 2 +- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index ac724dc26ad..a50fb0fc690 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -16,7 +16,19 @@ void freeHooks (KDB * kdb, Key * errorKey) } } -static int initHooksGopts (KDB * kdb, Plugin * plugin) +static size_t getFunction(Plugin * plugin, const char * functionName, Key * errorKey) +{ + size_t result = elektraPluginGetFunction (plugin, "hooks/gopts/get"); + + if(result == 0) + { + ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Plugin '%s' does not implement function '%s'", plugin->name, functionName); + } + + return result; +} + +static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) { if (!plugin) { @@ -24,7 +36,11 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin) } kdb->hooks.gopts.plugin = plugin; - kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) elektraPluginGetFunction (plugin, "hooks/gopts/get"); + + if((kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) getFunction (plugin, "hooks/gopts/get", errorKey)) == NULL) + { + return -1; + } return 0; } @@ -59,10 +75,14 @@ int initHooks (KDB * kdb, KeySet * modules, const KeySet * contract, Key * error { freeHooks (kdb, errorKey); - if (isGoptsEnabledByContract (contract) && !initHooksGopts (kdb, loadPlugin ("gopts", modules, errorKey))) + if (isGoptsEnabledByContract (contract) && initHooksGopts (kdb, loadPlugin ("gopts", modules, errorKey), errorKey) != 0) { - ELEKTRA_ADD_INSTALLATION_WARNING (errorKey, "Hook for 'gopts' enabled but no plugin found"); + goto error; } return 0; + +error: + freeHooks (kdb, errorKey); + return -1; } diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index cd218b44b68..107a6688f53 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1002,7 +1002,7 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) // TODO (atmaxinger): improve if (initHooks (handle, handle->modules, contract, errorKey) == -1) { - ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Mounting hooks failed. Please see warning of concrete plugin"); + ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Initializing hooks failed. Please see warning of concrete plugin"); ksDel (elektraKs); goto error; } From 08bcf428c4554a6a20e9e5cf62f8102684813834 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 09:35:34 +0200 Subject: [PATCH 15/38] hooks: implement hack to avoid plugins setting errors --- src/libs/elektra/kdb.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 107a6688f53..cc5b237e7e6 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1000,6 +1000,15 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) } // TODO (atmaxinger): improve + bool existingError = keyGetMeta (errorKey, "error") != NULL; + + if (!existingError) + { + // set a dummy value to block errors + // any errors that occur will be converted into warnings + keySetMeta (errorKey, "error", "blocked"); + } + if (initHooks (handle, handle->modules, contract, errorKey) == -1) { ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Initializing hooks failed. Please see warning of concrete plugin"); @@ -1007,6 +1016,12 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) goto error; } + if (!existingError) + { + // remove dummy error again + keySetMeta (errorKey, "error", NULL); + } + // Step 5: process contract if (contract != NULL && !ensureContract (handle, contract, errorKey)) { From d9a01c495440b9631dd3d7e0a9b0ddbc06f5a54a Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 09:52:56 +0200 Subject: [PATCH 16/38] plugins: make sure function name does not contain '..' --- src/libs/elektra/hooks.c | 2 +- src/libs/elektra/plugin.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index a50fb0fc690..4ef6173dfe5 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -18,7 +18,7 @@ void freeHooks (KDB * kdb, Key * errorKey) static size_t getFunction(Plugin * plugin, const char * functionName, Key * errorKey) { - size_t result = elektraPluginGetFunction (plugin, "hooks/gopts/get"); + size_t result = elektraPluginGetFunction (plugin, functionName); if(result == 0) { diff --git a/src/libs/elektra/plugin.c b/src/libs/elektra/plugin.c index f861dc0e391..03c65e9e1f6 100644 --- a/src/libs/elektra/plugin.c +++ b/src/libs/elektra/plugin.c @@ -153,7 +153,7 @@ int elektraPluginClose (Plugin * handle, Key * errorKey) * Retrieves a function exported by a plugin. * * @param plugin Plugin handle - * @param name Function name + * @param name Function name. Must be a valid key name suffix. May not contain the sequence '..' * @return Pointer to function. NULL if function not found or not enough memory available */ size_t elektraPluginGetFunction (Plugin * plugin, const char * name) @@ -161,13 +161,21 @@ size_t elektraPluginGetFunction (Plugin * plugin, const char * name) ELEKTRA_NOT_NULL (plugin); ELEKTRA_NOT_NULL (name); + if (strstr(name, "..") != NULL) + { + // The sequence ".." is contained in the key. + // For security and stability purposes we do not allow that. + return 0; + } + KeySet * exports = ksNew (0, KS_END); Key * pk = keyNew ("system:/elektra/modules", KEY_END); keyAddBaseName (pk, plugin->name); plugin->kdbGet (plugin, exports, pk); ksRewind (exports); keyAddBaseName (pk, "exports"); - keyAddName (pk, name); // we may not want to escape for hooks exports + keyAddName (pk, name); + Key * keyFunction = ksLookup (exports, pk, 0); if (!keyFunction) { From f95019e9c250cc9b6e3d4225641553d1384b7fd4 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 19 Sep 2022 07:53:08 +0000 Subject: [PATCH 17/38] Restyled by clang-format --- src/libs/elektra/hooks.c | 6 +++--- src/libs/elektra/plugin.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 4ef6173dfe5..ee9fad261a6 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -16,11 +16,11 @@ void freeHooks (KDB * kdb, Key * errorKey) } } -static size_t getFunction(Plugin * plugin, const char * functionName, Key * errorKey) +static size_t getFunction (Plugin * plugin, const char * functionName, Key * errorKey) { size_t result = elektraPluginGetFunction (plugin, functionName); - if(result == 0) + if (result == 0) { ELEKTRA_ADD_INSTALLATION_WARNINGF (errorKey, "Plugin '%s' does not implement function '%s'", plugin->name, functionName); } @@ -37,7 +37,7 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) kdb->hooks.gopts.plugin = plugin; - if((kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) getFunction (plugin, "hooks/gopts/get", errorKey)) == NULL) + if ((kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) getFunction (plugin, "hooks/gopts/get", errorKey)) == NULL) { return -1; } diff --git a/src/libs/elektra/plugin.c b/src/libs/elektra/plugin.c index 03c65e9e1f6..655a6a950af 100644 --- a/src/libs/elektra/plugin.c +++ b/src/libs/elektra/plugin.c @@ -161,7 +161,7 @@ size_t elektraPluginGetFunction (Plugin * plugin, const char * name) ELEKTRA_NOT_NULL (plugin); ELEKTRA_NOT_NULL (name); - if (strstr(name, "..") != NULL) + if (strstr (name, "..") != NULL) { // The sequence ".." is contained in the key. // For security and stability purposes we do not allow that. From e39ea2161b9021d58d0cc102aea71ff8ec288309 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 15:38:14 +0200 Subject: [PATCH 18/38] hooks: expose config to initHooks --- src/include/kdbprivate.h | 2 +- src/libs/elektra/hooks.c | 2 +- src/libs/elektra/kdb.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/kdbprivate.h b/src/include/kdbprivate.h index bdc6dcf133b..3268642c9b8 100644 --- a/src/include/kdbprivate.h +++ b/src/include/kdbprivate.h @@ -575,7 +575,7 @@ int mountModules (KDB * kdb, KeySet * modules, Key * errorKey); int mountVersion (KDB * kdb, Key * errorKey); int mountGlobals (KDB * kdb, KeySet * keys, KeySet * modules, Key * errorKey); int mountBackend (KDB * kdb, const Key * mountpoint, Plugin * backend); -int initHooks (KDB * kdb, KeySet * modules, const KeySet * contract, Key * errorKey); +int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey); void freeHooks (KDB * kdb, Key * errorKey); const Key * mountGetMountpoint (KDB * handle, Key * where); diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index ee9fad261a6..3257ba8554d 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -71,7 +71,7 @@ static bool isGoptsEnabledByContract (const KeySet * contract) return isEnabled; } -int initHooks (KDB * kdb, KeySet * modules, const KeySet * contract, Key * errorKey) +int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey) { freeHooks (kdb, errorKey); diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index cc5b237e7e6..226bf11e234 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1009,7 +1009,7 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) keySetMeta (errorKey, "error", "blocked"); } - if (initHooks (handle, handle->modules, contract, errorKey) == -1) + if (initHooks (handle, elektraKs, handle->modules, contract, errorKey) == -1) { ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Initializing hooks failed. Please see warning of concrete plugin"); ksDel (elektraKs); From 546a258749c7b8c8ecf4d88fd75b5bb5542f7476 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 15:41:59 +0200 Subject: [PATCH 19/38] hooks: use singular form in keys --- doc/dev/hooks.md | 4 ++-- src/libs/elektra/hooks.c | 2 +- src/plugins/gopts/gopts.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index e419a716dce..e77c329b422 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -11,9 +11,9 @@ A symlink replacing the shared library file of the plugin could be used to chang ## Interface of the hooks If a plugin should be able to act upon a hook, it must export all the functions that the hook requires. -These exports are of the form `system:/elektra/modules//exports/hooks//`. +These exports are of the form `system:/elektra/modules//exports/hook//`. -For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefore has to export `system:/elektra/modules//exports/hooks/gopts/get`. +For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefore has to export `system:/elektra/modules//exports/hook/gopts/get`. Other hooks (e.g. `spec`) might require multiple exported functions. diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 3257ba8554d..3af3e1560c3 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -37,7 +37,7 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) kdb->hooks.gopts.plugin = plugin; - if ((kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) getFunction (plugin, "hooks/gopts/get", errorKey)) == NULL) + if ((kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) getFunction (plugin, "hook/gopts/get", errorKey)) == NULL) { return -1; } diff --git a/src/plugins/gopts/gopts.c b/src/plugins/gopts/gopts.c index e867c0e5956..ccc6bc2e271 100644 --- a/src/plugins/gopts/gopts.c +++ b/src/plugins/gopts/gopts.c @@ -43,7 +43,7 @@ int elektraGOptsGet (Plugin * handle, KeySet * returned, Key * parentKey) ksNew (30, keyNew ("system:/elektra/modules/gopts", KEY_VALUE, "gopts plugin waits for your orders", KEY_END), keyNew ("system:/elektra/modules/gopts/exports", KEY_END), keyNew ("system:/elektra/modules/gopts/exports/get", KEY_FUNC, elektraGOptsGet, KEY_END), - keyNew ("system:/elektra/modules/gopts/exports/hooks/gopts/get", KEY_FUNC, elektraGOptsGet, KEY_END), + keyNew ("system:/elektra/modules/gopts/exports/hook/gopts/get", KEY_FUNC, elektraGOptsGet, KEY_END), #include ELEKTRA_README keyNew ("system:/elektra/modules/gopts/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END); ksAppend (returned, contract); From 3549be8e654ae4c1c09c67c62d4eea5cc217acc1 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 15:53:11 +0200 Subject: [PATCH 20/38] Update release notes --- doc/news/_preparation_next_release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/news/_preparation_next_release.md b/doc/news/_preparation_next_release.md index c9570a2fcb3..0db8bc9a2f5 100644 --- a/doc/news/_preparation_next_release.md +++ b/doc/news/_preparation_next_release.md @@ -164,7 +164,7 @@ _(Michael Tucek)_ ### New Backend - Improve [description of plugin framework](doc/dev/plugins-framework.md). -- <> +- Implement [hooks](doc/decisions/global_plugins.md). _(Maximilian Irlinger @atmaxinger)_ - <> - <> - <> From 25475b205f28f7b0bd7ce883fcf6e58a5bfd033c Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 18:28:06 +0200 Subject: [PATCH 21/38] hooks: create plugin config from contract --- src/libs/elektra/hooks.c | 53 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 3af3e1560c3..e26068cf444 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -45,11 +45,56 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) return 0; } -static Plugin * loadPlugin (const char * pluginName, KeySet * modules, Key * errorKey) +static KeySet * getPluginConfigFromContract(const char * pluginName, const KeySet * contract) +{ + KeySet * tmpContract = ksDup (contract); + KeySet * config = ksNew (0, KS_END); + + Key * mountContractRoot = keyNew ("system:/elektra/contract/mountglobal", KEY_END); + Key * pluginConfigRoot = keyNew ("user:/", KEY_END); + + for (elektraCursor it = ksFindHierarchy (tmpContract, mountContractRoot, NULL); it < ksGetSize (tmpContract); it++) + { + Key * cur = ksAtCursor (tmpContract, it); + if (keyIsDirectlyBelow (mountContractRoot, cur) == 1) + { + const char * pluginNameOfConfig = keyBaseName (cur); + if(strcmp (pluginName, pluginNameOfConfig) != 0) + { + break; + } + + KeySet * pluginConfig = ksCut (tmpContract, cur); + + // increment ref count, because cur is part of pluginConfig and + // we hold a reference to cur that is still needed (via pluginName) + keyIncRef (cur); + ksRename (pluginConfig, cur, pluginConfigRoot); + ksAppend (config, pluginConfig); + + // we need to delete cur separately, because it was ksCut() from contract + // we also need to decrement the ref count, because it was incremented above + keyDecRef (cur); + keyDel (cur); + + --it; + } + } + + keyDel (mountContractRoot); + keyDel (pluginConfigRoot); + ksDel (tmpContract); + + return config; +} + +static Plugin * loadPlugin (const char * pluginName, KeySet * global, KeySet * modules, const KeySet * contract, Key * errorKey) { Key * openKey = keyDup (errorKey, KEY_CP_ALL); - Plugin * plugin = elektraPluginOpen (pluginName, modules, ksNew (0, KS_END), openKey); + KeySet * config = getPluginConfigFromContract(pluginName, contract); + + Plugin * plugin = elektraPluginOpen (pluginName, modules, config, openKey); if (!plugin) { @@ -59,6 +104,8 @@ static Plugin * loadPlugin (const char * pluginName, KeySet * modules, Key * err return NULL; } + plugin->global = global; + return plugin; } @@ -75,7 +122,7 @@ int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet { freeHooks (kdb, errorKey); - if (isGoptsEnabledByContract (contract) && initHooksGopts (kdb, loadPlugin ("gopts", modules, errorKey), errorKey) != 0) + if (isGoptsEnabledByContract (contract) && initHooksGopts (kdb, loadPlugin ("gopts", kdb->global, modules, contract, errorKey), errorKey) != 0) { goto error; } From dcf6bc2cf9dc499fe85cd3b86640ad07429830a5 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 18:32:51 +0200 Subject: [PATCH 22/38] hooks: castrate global plugin handlers, but leave them in there for debugging purposes --- src/libs/elektra/global.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/elektra/global.c b/src/libs/elektra/global.c index 346f996ccf4..6f0087a0fe7 100644 --- a/src/libs/elektra/global.c +++ b/src/libs/elektra/global.c @@ -20,7 +20,7 @@ int elektraGlobalGet (KDB * handle, KeySet * ks, Key * parentKey, int position, Plugin * plugin; if (handle && (plugin = handle->globalPlugins[position][subPosition])) { - ret = plugin->kdbGet (plugin, ks, parentKey); + //ret = plugin->kdbGet (plugin, ks, parentKey); } return ret; } @@ -31,7 +31,7 @@ int elektraGlobalSet (KDB * handle, KeySet * ks, Key * parentKey, int position, Plugin * plugin; if (handle && (plugin = handle->globalPlugins[position][subPosition])) { - ret = plugin->kdbSet (plugin, ks, parentKey); + //ret = plugin->kdbSet (plugin, ks, parentKey); } return ret; } @@ -42,7 +42,7 @@ int elektraGlobalError (KDB * handle, KeySet * ks, Key * parentKey, int position Plugin * plugin; if (handle && (plugin = handle->globalPlugins[position][subPosition])) { - ret = plugin->kdbError (plugin, ks, parentKey); + //ret = plugin->kdbError (plugin, ks, parentKey); } return ret; } From 1b21b6f413c0aa2f0163c3013ab1f4b886330be2 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 18:39:04 +0200 Subject: [PATCH 23/38] Update src/libs/elektra/plugin.c Co-authored-by: Markus Raab --- src/libs/elektra/plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/elektra/plugin.c b/src/libs/elektra/plugin.c index 655a6a950af..ce8868bb41f 100644 --- a/src/libs/elektra/plugin.c +++ b/src/libs/elektra/plugin.c @@ -163,7 +163,7 @@ size_t elektraPluginGetFunction (Plugin * plugin, const char * name) if (strstr (name, "..") != NULL) { - // The sequence ".." is contained in the key. + // The sequence ".." is contained in the name. // For security and stability purposes we do not allow that. return 0; } From a64a5b597d0b39dabe671ad373e92c0be046e311 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 18:39:40 +0200 Subject: [PATCH 24/38] Update doc/dev/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/dev/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index e77c329b422..c209e18cf82 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -15,7 +15,7 @@ These exports are of the form `system:/elektra/modules//exports/hoo For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefore has to export `system:/elektra/modules//exports/hook/gopts/get`. -Other hooks (e.g. `spec`) might require multiple exported functions. +Other hooks (e.g. `spec`) require multiple exported functions. ## Lifecycle From e64c8d2ec3678b91731cddab56c7446da0ed149d Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Mon, 19 Sep 2022 18:40:21 +0200 Subject: [PATCH 25/38] Update doc/dev/hooks.md Co-authored-by: Markus Raab --- doc/dev/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index c209e18cf82..7294f4a9e38 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -2,7 +2,7 @@ Hooks are central points in the KDB lifecycle, where specialized plugins are called. -## Selecting which Plugin will be used for a specific hook +## Selecting which Plugin will be Used for a Specific Hook Currently, the names of the plugins are hard-coded. This decision was made, because these plugins are meant to fulfil very specific purposes. From 0400df1ddc6139e301b3dccac1583c30e034928d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 19 Sep 2022 16:40:34 +0000 Subject: [PATCH 26/38] Restyled by clang-format --- src/libs/elektra/global.c | 6 +++--- src/libs/elektra/hooks.c | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libs/elektra/global.c b/src/libs/elektra/global.c index 6f0087a0fe7..17925dfdfe4 100644 --- a/src/libs/elektra/global.c +++ b/src/libs/elektra/global.c @@ -20,7 +20,7 @@ int elektraGlobalGet (KDB * handle, KeySet * ks, Key * parentKey, int position, Plugin * plugin; if (handle && (plugin = handle->globalPlugins[position][subPosition])) { - //ret = plugin->kdbGet (plugin, ks, parentKey); + // ret = plugin->kdbGet (plugin, ks, parentKey); } return ret; } @@ -31,7 +31,7 @@ int elektraGlobalSet (KDB * handle, KeySet * ks, Key * parentKey, int position, Plugin * plugin; if (handle && (plugin = handle->globalPlugins[position][subPosition])) { - //ret = plugin->kdbSet (plugin, ks, parentKey); + // ret = plugin->kdbSet (plugin, ks, parentKey); } return ret; } @@ -42,7 +42,7 @@ int elektraGlobalError (KDB * handle, KeySet * ks, Key * parentKey, int position Plugin * plugin; if (handle && (plugin = handle->globalPlugins[position][subPosition])) { - //ret = plugin->kdbError (plugin, ks, parentKey); + // ret = plugin->kdbError (plugin, ks, parentKey); } return ret; } diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index e26068cf444..0d17ce2e7a1 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -45,7 +45,7 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) return 0; } -static KeySet * getPluginConfigFromContract(const char * pluginName, const KeySet * contract) +static KeySet * getPluginConfigFromContract (const char * pluginName, const KeySet * contract) { KeySet * tmpContract = ksDup (contract); KeySet * config = ksNew (0, KS_END); @@ -59,7 +59,7 @@ static KeySet * getPluginConfigFromContract(const char * pluginName, const KeySe if (keyIsDirectlyBelow (mountContractRoot, cur) == 1) { const char * pluginNameOfConfig = keyBaseName (cur); - if(strcmp (pluginName, pluginNameOfConfig) != 0) + if (strcmp (pluginName, pluginNameOfConfig) != 0) { break; } @@ -92,7 +92,7 @@ static Plugin * loadPlugin (const char * pluginName, KeySet * global, KeySet * m { Key * openKey = keyDup (errorKey, KEY_CP_ALL); - KeySet * config = getPluginConfigFromContract(pluginName, contract); + KeySet * config = getPluginConfigFromContract (pluginName, contract); Plugin * plugin = elektraPluginOpen (pluginName, modules, config, openKey); @@ -122,7 +122,8 @@ int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet { freeHooks (kdb, errorKey); - if (isGoptsEnabledByContract (contract) && initHooksGopts (kdb, loadPlugin ("gopts", kdb->global, modules, contract, errorKey), errorKey) != 0) + if (isGoptsEnabledByContract (contract) && + initHooksGopts (kdb, loadPlugin ("gopts", kdb->global, modules, contract, errorKey), errorKey) != 0) { goto error; } From b20c324c242a9dc12dfc1c49430a25cf02fabf56 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Tue, 20 Sep 2022 10:53:08 +0200 Subject: [PATCH 27/38] hooks: add comments to public facing functions --- src/libs/elektra/hooks.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 0d17ce2e7a1..52ab2f8b47d 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -8,6 +8,12 @@ #include +/** + * Uninitializes and frees all hooks in the passed KDB handle. + * + * @param kdb the KDB handle where the hooks should be freed + * @param errorKey the key which holds errors and warnings which were issued + */ void freeHooks (KDB * kdb, Key * errorKey) { if (kdb->hooks.gopts.plugin != NULL) @@ -59,6 +65,11 @@ static KeySet * getPluginConfigFromContract (const char * pluginName, const KeyS if (keyIsDirectlyBelow (mountContractRoot, cur) == 1) { const char * pluginNameOfConfig = keyBaseName (cur); + + // only handle config for the specified plugin + // we might be able to replace this check by modifying the key mountContractRoot, + // but I just copied this function from the previous global plugins implementation + // and it works for now. if (strcmp (pluginName, pluginNameOfConfig) != 0) { break; @@ -118,6 +129,18 @@ static bool isGoptsEnabledByContract (const KeySet * contract) return isEnabled; } +/** + * Initializes the hooks stored in the passed KDB handle. + * If the handle already contains initialized hooks, they will be reinitialized, including unloading and loading of their plugins. + * Parameters @p config and @p contract will be used to determine which hooks to populate. + * + * @param kdb the KDB instance where the hooks should be initialized + * @param config KeySet containing the current config in @p system:/elektra namespace + * @param modules the current list of loaded modules + * @param contract the contract passed to @p kdbOpen + * @param errorKey the key which holds errors and warnings which were issued + * @return 0 on success, -1 on failure + */ int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey) { freeHooks (kdb, errorKey); From 7e25bc979cb715d130fb6cf7b3188f232871871c Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Tue, 20 Sep 2022 11:05:17 +0200 Subject: [PATCH 28/38] plugins: add warning if function can not be loaded because it contains '..'. --- src/libs/elektra/plugin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/elektra/plugin.c b/src/libs/elektra/plugin.c index ce8868bb41f..c612f6851b2 100644 --- a/src/libs/elektra/plugin.c +++ b/src/libs/elektra/plugin.c @@ -165,6 +165,7 @@ size_t elektraPluginGetFunction (Plugin * plugin, const char * name) { // The sequence ".." is contained in the name. // For security and stability purposes we do not allow that. + ELEKTRA_LOG_WARNING ("Can't get function '%s' from plugin because '..' is not allowed in function name", name); return 0; } From 6bbb17617d28e73765724bb6a6b2cef013d1a176 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Tue, 20 Sep 2022 13:56:48 +0200 Subject: [PATCH 29/38] hooks: change decision file --- doc/decisions/README.md | 2 +- doc/decisions/array.md | 2 +- doc/decisions/ensure.md | 2 +- doc/decisions/{global_plugins.md => hooks.md} | 12 +++++++++--- doc/dev/hooks.md | 2 +- doc/news/_preparation_next_release.md | 2 +- 6 files changed, 14 insertions(+), 8 deletions(-) rename doc/decisions/{global_plugins.md => hooks.md} (81%) diff --git a/doc/decisions/README.md b/doc/decisions/README.md index fe268903feb..9b06bfe25d6 100644 --- a/doc/decisions/README.md +++ b/doc/decisions/README.md @@ -46,7 +46,7 @@ section here. ## In Progress -- [Global Plugins](global_plugins.md) (@mpranj) +- [Hooks](hooks.md) (@atmaxinger) - [Ensure](ensure.md) (@kodebach) - [Capabilities](capabilities.md) (@markus2330) - [Error Semantics](error_semantics.md) (API) diff --git a/doc/decisions/array.md b/doc/decisions/array.md index 1df5c91bc04..fe32d44a632 100644 --- a/doc/decisions/array.md +++ b/doc/decisions/array.md @@ -108,7 +108,7 @@ The `spec` plugin should check if it is a valid array, i.e.: ## Related Decisions -- [Global Plugins](global_plugins.md) +- [Hooks](hooks.md) - [Global Validation](global_validation.md) - [Base Names](base_name.md) - [Metadata in Spec Namespace](spec_metadata.md) diff --git a/doc/decisions/ensure.md b/doc/decisions/ensure.md index c46d47ad7c6..8c64ba60102 100644 --- a/doc/decisions/ensure.md +++ b/doc/decisions/ensure.md @@ -83,6 +83,6 @@ invocations. Contract `KeySet`s only contain `Key`s below ## Related Decisions -- [Global Plugins](global_plugins.md) +- [Hooks](hooks.md) ## Notes diff --git a/doc/decisions/global_plugins.md b/doc/decisions/hooks.md similarity index 81% rename from doc/decisions/global_plugins.md rename to doc/decisions/hooks.md index 8c46459ad22..6e3e245656f 100644 --- a/doc/decisions/global_plugins.md +++ b/doc/decisions/hooks.md @@ -1,7 +1,8 @@ -# Global Plugins +# Hooks in KDB ## Problem +In the current global plugins implementation: - Notification does not happen once after final commit, but for every plugin - Problems in spec plugin @@ -11,21 +12,23 @@ We need to clean up and simplify the placement. ## Constraints -- Plugin interface should be the same. Many plugins, e.g. dbus, should work +- Plugin interface should be the same. Many plugins, where appropriate, e.g. dbus, should work as global plugins w/o any change in code (i.e. only changes in contract) + - Global plugins might depend on specific applications or specific mount points (it should be possible to enforce global plugins for specific applications). ## Assumptions -- Elektra is useful with following types of global plugins: +- Elektra is useful with following types of plugins: - mmap - spec - gopts - receiving of notifications (internalnotification) - sending of notifications (dbus, ...) + - recording of changes - There are not too many types of global plugins, not more than 10 ## Considered Alternatives @@ -44,6 +47,8 @@ These hooks are not shared, so no `list` plugin is needed. Installed plugins will be used. +In the beginning, we'll hardcode the names of the plugins. For changing those plugins symlinks will have to be used. + ## Rationale - allows adding more types of plugins later, also post-1.0 @@ -57,6 +62,7 @@ Installed plugins will be used. - remove `list` plugin - remove plugins that stop working or disallow global positioning for them - call `spec` as needed several times +- remove current global plugins mechanism ## Related Decisions diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index 7294f4a9e38..ea93a15cb19 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -5,7 +5,7 @@ Hooks are central points in the KDB lifecycle, where specialized plugins are cal ## Selecting which Plugin will be Used for a Specific Hook Currently, the names of the plugins are hard-coded. -This decision was made, because these plugins are meant to fulfil very specific purposes. +This [decision](../decisions/hooks.md) was made, because these plugins are meant to fulfil very specific purposes. A symlink replacing the shared library file of the plugin could be used to change the implementation. ## Interface of the hooks diff --git a/doc/news/_preparation_next_release.md b/doc/news/_preparation_next_release.md index 0db8bc9a2f5..078107fb0e3 100644 --- a/doc/news/_preparation_next_release.md +++ b/doc/news/_preparation_next_release.md @@ -164,7 +164,7 @@ _(Michael Tucek)_ ### New Backend - Improve [description of plugin framework](doc/dev/plugins-framework.md). -- Implement [hooks](doc/decisions/global_plugins.md). _(Maximilian Irlinger @atmaxinger)_ +- Implement [hooks](doc/decisions/hooks.md). _(Maximilian Irlinger @atmaxinger)_ - <> - <> - <> From bf67ae57b1155f976144d27796e0fbf89911b95e Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Tue, 20 Sep 2022 21:41:28 +0200 Subject: [PATCH 30/38] Update src/libs/elektra/hooks.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- src/libs/elektra/hooks.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 52ab2f8b47d..510dd50d829 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -51,6 +51,14 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) return 0; } +/** + * Extracts the config for a single plugin from the contract + * + * The config must be below system:/elektra/contract/mountglobal/ and will be moved to below user:/ + * + * @param pluginName The name of the plugin for which the config will be extracted + * @param contract The contract from which the config is extracted + */ static KeySet * getPluginConfigFromContract (const char * pluginName, const KeySet * contract) { KeySet * tmpContract = ksDup (contract); From 44fa8e5c7e5ed8ebfae7c9df99453d5f25801566 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Tue, 20 Sep 2022 22:02:11 +0200 Subject: [PATCH 31/38] hooks: block errors in initHooks --- src/libs/elektra/hooks.c | 22 ++++++++++++++++++++++ src/libs/elektra/kdb.c | 15 --------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 510dd50d829..7375ec8ccfc 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -151,6 +151,15 @@ static bool isGoptsEnabledByContract (const KeySet * contract) */ int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet * contract, Key * errorKey) { + bool existingError = ksLookupByName (keyMeta (errorKey), "meta:/error", 0) != NULL; + + if (!existingError) + { + // set a dummy value to block errors + // any errors that occur will be converted into warnings + keySetMeta (errorKey, "meta:/error", "blocked"); + } + freeHooks (kdb, errorKey); if (isGoptsEnabledByContract (contract) && @@ -159,9 +168,22 @@ int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet goto error; } + if (!existingError) + { + // remove dummy error again + keySetMeta (errorKey, "meta:/error", NULL); + } + return 0; error: freeHooks (kdb, errorKey); + + if (!existingError) + { + // remove dummy error again + keySetMeta (errorKey, "meta:/error", NULL); + } + return -1; } diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index 226bf11e234..ad12358f73b 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1000,15 +1000,6 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) } // TODO (atmaxinger): improve - bool existingError = keyGetMeta (errorKey, "error") != NULL; - - if (!existingError) - { - // set a dummy value to block errors - // any errors that occur will be converted into warnings - keySetMeta (errorKey, "error", "blocked"); - } - if (initHooks (handle, elektraKs, handle->modules, contract, errorKey) == -1) { ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Initializing hooks failed. Please see warning of concrete plugin"); @@ -1016,12 +1007,6 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) goto error; } - if (!existingError) - { - // remove dummy error again - keySetMeta (errorKey, "error", NULL); - } - // Step 5: process contract if (contract != NULL && !ensureContract (handle, contract, errorKey)) { From e4cc4b4e50ebc100672d6d596c3fad91a5359763 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Wed, 21 Sep 2022 11:13:11 +0200 Subject: [PATCH 32/38] hooks: create tests for getPluginConfigFromContract --- src/libs/elektra/hooks.c | 3 +- tests/ctest/CMakeLists.txt | 2 + tests/ctest/test_hooks.c | 80 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/ctest/test_hooks.c diff --git a/src/libs/elektra/hooks.c b/src/libs/elektra/hooks.c index 7375ec8ccfc..2ab23ff1808 100644 --- a/src/libs/elektra/hooks.c +++ b/src/libs/elektra/hooks.c @@ -54,7 +54,8 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey) /** * Extracts the config for a single plugin from the contract * - * The config must be below system:/elektra/contract/mountglobal/ and will be moved to below user:/ + * The config must be below system:/elektra/contract/mountglobal/ and will be moved to below user:/. + * It also must contain the key system:/elektra/contract/mountglobal/. * * @param pluginName The name of the plugin for which the config will be extracted * @param contract The contract from which the config is extracted diff --git a/tests/ctest/CMakeLists.txt b/tests/ctest/CMakeLists.txt index cad386ec362..b7c8e6853b3 100644 --- a/tests/ctest/CMakeLists.txt +++ b/tests/ctest/CMakeLists.txt @@ -37,5 +37,7 @@ target_link_elektra (test_cmerge elektra-merge) target_link_elektra (test_sha-256 elektra-ease) +target_link_elektra(test_hooks elektra-plugin) + # LibGit leaks memory set_property (TEST test_cmerge PROPERTY LABELS memleak) diff --git a/tests/ctest/test_hooks.c b/tests/ctest/test_hooks.c new file mode 100644 index 00000000000..49bcbbb2b80 --- /dev/null +++ b/tests/ctest/test_hooks.c @@ -0,0 +1,80 @@ +/** +* @file +* +* @brief +* +* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) +*/ + +#include "../../src/libs/elektra/hooks.c" +#include + +static void test_getPluginConfigFromContract_withConfigInContract (void) +{ + printf ("Executing %s\n", __func__); + + // Arrange + KeySet * contract = + ksNew (30, keyNew ("system:/elektra/something", KEY_VALUE, "3", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/myPlugin", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/myPlugin/someValue", KEY_VALUE, "1", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/myPlugin/someOtherValue", KEY_VALUE, "2", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin/someValue", KEY_VALUE, "1", KEY_END), + keyNew ("system:/elektra/myPlugin", KEY_END), + keyNew ("system:/elektra/myPlugin/shouldntSeeMe", KEY_VALUE, "5", KEY_END), + keyNew ("system:/elektra/record/enabled", KEY_VALUE, "0", KEY_END), KS_END); + + // Act + KeySet * result = getPluginConfigFromContract ("myPlugin", contract); + + // Assert + succeed_if (result != NULL, "result must not be NULL"); + succeed_if (ksGetSize (result) == 3, "expected resulting config to have 3 keys"); + succeed_if (ksLookupByName (result, "user:/", KDB_O_NONE) != NULL, "must contain key user:/"); + succeed_if (ksLookupByName (result, "user:/someValue", KDB_O_NONE) != NULL, "must contain key user:/someValue"); + succeed_if (ksLookupByName (result, "user:/someOtherValue", KDB_O_NONE) != NULL, "must contain key user:/someOtherValue"); + + ksDel(contract); + ksDel (result); +} + +static void test_getPluginConfigFromContract_withoutConfigInContract (void) +{ + printf ("Executing %s\n", __func__); + + // Arrange + KeySet * contract = + ksNew (30, keyNew ("system:/elektra/something", KEY_VALUE, "3", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin/someValue", KEY_VALUE, "1", KEY_END), + keyNew ("system:/elektra/myPlugin", KEY_END), + keyNew ("system:/elektra/myPlugin/shouldntSeeMe", KEY_VALUE, "5", KEY_END), + keyNew ("system:/elektra/record/enabled", KEY_VALUE, "0", KEY_END), KS_END); + + // Act + KeySet * result = getPluginConfigFromContract ("myPlugin", contract); + + // Assert + succeed_if (result != NULL, "result must not be NULL"); + succeed_if (ksGetSize (result) == 0, "expected resulting config to have 0 keys"); + + ksDel(contract); + ksDel (result); +} + +int main(int argc, char ** argv) +{ + printf ("HOOKS TESTS\n"); + printf ("=================\n\n"); + + init (argc, argv); + test_getPluginConfigFromContract_withConfigInContract (); + test_getPluginConfigFromContract_withoutConfigInContract(); + + printf ("\ntest_hooks RESULTS: %d test(s) done. %d error(s).\n", nbTest, nbError); + + return nbError; +} + + From b1e21ee6c7c778d8296a27cd2c163f6495f82fb5 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Wed, 21 Sep 2022 17:27:06 +0200 Subject: [PATCH 33/38] hooks: add tests for most important functions --- tests/ctest/test_hooks.c | 109 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/ctest/test_hooks.c b/tests/ctest/test_hooks.c index 49bcbbb2b80..6f157ea8d80 100644 --- a/tests/ctest/test_hooks.c +++ b/tests/ctest/test_hooks.c @@ -63,6 +63,110 @@ static void test_getPluginConfigFromContract_withoutConfigInContract (void) ksDel (result); } +static void test_loadPlugin(void) +{ + printf ("Executing %s\n", __func__); + + // Arrange + KeySet * global = ksNew (0, KS_END); + KeySet * modules = ksNew (0, KS_END); + KeySet * contract = ksNew (30, keyNew ("system:/elektra/contract/mountglobal/gopts", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/gopts/offset", KEY_VALUE, "1", KEY_END), KS_END); + + Key * errorKey = keyNew ("system:/hello", KEY_END); + + // Act + Plugin * plugin = loadPlugin ("gopts", global, modules, contract, errorKey); + + // Assert + succeed_if (plugin != NULL, "must be able to load plugin"); + succeed_if (plugin->modules == modules, "must set modules"); + succeed_if (plugin->global == global, "must set global"); + succeed_if (ksGetSize (plugin->config) == 2, "config size must be 2"); + + ksDel (global); + ksDel (modules); + ksDel (contract); + elektraPluginClose (plugin, errorKey); + keyDel (errorKey); +} + +static void test_loadPlugin_inexistent(void) +{ + printf ("Executing %s\n", __func__); + + // Arrange + KeySet * global = ksNew (0, KS_END); + KeySet * modules = ksNew (0, KS_END); + KeySet * contract = ksNew (0, KS_END); + + Key * errorKey = keyNew ("system:/hello", KEY_END); + + // Act + Plugin * plugin = loadPlugin ("thisPluginSurelyDoesNotExist123", global, modules, contract, errorKey); + + // Assert + succeed_if (plugin == NULL, "must not load plugin"); + + ksDel (global); + ksDel (modules); + ksDel (contract); + keyDel (errorKey); +} + +static void test_isGoptsEnabledByContract(bool shouldBeEnabled) +{ + printf ("Executing %s with shouldBeEnabled=%d\n", __func__, shouldBeEnabled); + + // Arrange + KeySet * contract = ksNew (1, KS_END); + if(shouldBeEnabled) + { + ksAppendKey (contract, keyNew ("system:/elektra/contract/mountglobal/gopts", KEY_END)); + } + + // Act + bool result = isGoptsEnabledByContract (contract); + + // Assert + succeed_if_fmt (result == shouldBeEnabled, "result is %d but should be %d", result, shouldBeEnabled); + + ksDel (contract); +} + +static void test_initHooks_shouldInitAllHooksWithoutFailure(void) +{ + printf ("Executing %s\n", __func__); + + // Arrange + KDB * kdb = elektraCalloc (sizeof (struct _KDB)); + KeySet * config = ksNew (0, KS_END); + KeySet * modules = ksNew (0, KS_END); + KeySet * contract = ksNew (1, keyNew ("system:/elektra/contract/mountglobal/gopts", KEY_END), KS_END); + + kdb->global = ksNew (0, KS_END); + kdb->modules = modules; + + Key * errorKey = keyNew ("system:/elektra", KS_END); + + // Act + int result = initHooks (kdb, config, modules, contract, errorKey); + + // Assert + KeySet * meta = keyMeta (errorKey); + + succeed_if (result == 0, "result should be 0"); + succeed_if (ksGetSize (meta) == 0, "error key should not have meta data"); + succeed_if (kdb->hooks.gopts.plugin != NULL, "gopts plugin should be loaded"); + succeed_if (kdb->hooks.gopts.kdbHookGoptsGet != NULL, "gopts.kdbHookGoptsGet should be found"); + + ksDel (config); + ksDel (modules); + ksDel (contract); + + elektraFree (kdb); +} + int main(int argc, char ** argv) { printf ("HOOKS TESTS\n"); @@ -71,6 +175,11 @@ int main(int argc, char ** argv) init (argc, argv); test_getPluginConfigFromContract_withConfigInContract (); test_getPluginConfigFromContract_withoutConfigInContract(); + test_loadPlugin(); + test_loadPlugin_inexistent(); + test_isGoptsEnabledByContract(true); + test_isGoptsEnabledByContract(false); + test_initHooks_shouldInitAllHooksWithoutFailure(); printf ("\ntest_hooks RESULTS: %d test(s) done. %d error(s).\n", nbTest, nbError); From bcd7a023553dd52d26da99266526edd640f917e0 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 21 Sep 2022 15:27:31 +0000 Subject: [PATCH 34/38] Restyled by clang-format --- tests/ctest/test_hooks.c | 74 +++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/tests/ctest/test_hooks.c b/tests/ctest/test_hooks.c index 6f157ea8d80..dca13acd3a9 100644 --- a/tests/ctest/test_hooks.c +++ b/tests/ctest/test_hooks.c @@ -1,10 +1,10 @@ /** -* @file -* -* @brief -* -* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) -*/ + * @file + * + * @brief + * + * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) + */ #include "../../src/libs/elektra/hooks.c" #include @@ -14,16 +14,15 @@ static void test_getPluginConfigFromContract_withConfigInContract (void) printf ("Executing %s\n", __func__); // Arrange - KeySet * contract = - ksNew (30, keyNew ("system:/elektra/something", KEY_VALUE, "3", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/myPlugin", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/myPlugin/someValue", KEY_VALUE, "1", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/myPlugin/someOtherValue", KEY_VALUE, "2", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/otherPlugin", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/otherPlugin/someValue", KEY_VALUE, "1", KEY_END), - keyNew ("system:/elektra/myPlugin", KEY_END), - keyNew ("system:/elektra/myPlugin/shouldntSeeMe", KEY_VALUE, "5", KEY_END), - keyNew ("system:/elektra/record/enabled", KEY_VALUE, "0", KEY_END), KS_END); + KeySet * contract = ksNew (30, keyNew ("system:/elektra/something", KEY_VALUE, "3", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/myPlugin", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/myPlugin/someValue", KEY_VALUE, "1", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/myPlugin/someOtherValue", KEY_VALUE, "2", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin/someValue", KEY_VALUE, "1", KEY_END), + keyNew ("system:/elektra/myPlugin", KEY_END), + keyNew ("system:/elektra/myPlugin/shouldntSeeMe", KEY_VALUE, "5", KEY_END), + keyNew ("system:/elektra/record/enabled", KEY_VALUE, "0", KEY_END), KS_END); // Act KeySet * result = getPluginConfigFromContract ("myPlugin", contract); @@ -35,7 +34,7 @@ static void test_getPluginConfigFromContract_withConfigInContract (void) succeed_if (ksLookupByName (result, "user:/someValue", KDB_O_NONE) != NULL, "must contain key user:/someValue"); succeed_if (ksLookupByName (result, "user:/someOtherValue", KDB_O_NONE) != NULL, "must contain key user:/someOtherValue"); - ksDel(contract); + ksDel (contract); ksDel (result); } @@ -44,13 +43,12 @@ static void test_getPluginConfigFromContract_withoutConfigInContract (void) printf ("Executing %s\n", __func__); // Arrange - KeySet * contract = - ksNew (30, keyNew ("system:/elektra/something", KEY_VALUE, "3", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/otherPlugin", KEY_END), - keyNew ("system:/elektra/contract/mountglobal/otherPlugin/someValue", KEY_VALUE, "1", KEY_END), - keyNew ("system:/elektra/myPlugin", KEY_END), - keyNew ("system:/elektra/myPlugin/shouldntSeeMe", KEY_VALUE, "5", KEY_END), - keyNew ("system:/elektra/record/enabled", KEY_VALUE, "0", KEY_END), KS_END); + KeySet * contract = ksNew (30, keyNew ("system:/elektra/something", KEY_VALUE, "3", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin", KEY_END), + keyNew ("system:/elektra/contract/mountglobal/otherPlugin/someValue", KEY_VALUE, "1", KEY_END), + keyNew ("system:/elektra/myPlugin", KEY_END), + keyNew ("system:/elektra/myPlugin/shouldntSeeMe", KEY_VALUE, "5", KEY_END), + keyNew ("system:/elektra/record/enabled", KEY_VALUE, "0", KEY_END), KS_END); // Act KeySet * result = getPluginConfigFromContract ("myPlugin", contract); @@ -59,11 +57,11 @@ static void test_getPluginConfigFromContract_withoutConfigInContract (void) succeed_if (result != NULL, "result must not be NULL"); succeed_if (ksGetSize (result) == 0, "expected resulting config to have 0 keys"); - ksDel(contract); + ksDel (contract); ksDel (result); } -static void test_loadPlugin(void) +static void test_loadPlugin (void) { printf ("Executing %s\n", __func__); @@ -91,7 +89,7 @@ static void test_loadPlugin(void) keyDel (errorKey); } -static void test_loadPlugin_inexistent(void) +static void test_loadPlugin_inexistent (void) { printf ("Executing %s\n", __func__); @@ -114,13 +112,13 @@ static void test_loadPlugin_inexistent(void) keyDel (errorKey); } -static void test_isGoptsEnabledByContract(bool shouldBeEnabled) +static void test_isGoptsEnabledByContract (bool shouldBeEnabled) { printf ("Executing %s with shouldBeEnabled=%d\n", __func__, shouldBeEnabled); // Arrange KeySet * contract = ksNew (1, KS_END); - if(shouldBeEnabled) + if (shouldBeEnabled) { ksAppendKey (contract, keyNew ("system:/elektra/contract/mountglobal/gopts", KEY_END)); } @@ -134,7 +132,7 @@ static void test_isGoptsEnabledByContract(bool shouldBeEnabled) ksDel (contract); } -static void test_initHooks_shouldInitAllHooksWithoutFailure(void) +static void test_initHooks_shouldInitAllHooksWithoutFailure (void) { printf ("Executing %s\n", __func__); @@ -167,23 +165,21 @@ static void test_initHooks_shouldInitAllHooksWithoutFailure(void) elektraFree (kdb); } -int main(int argc, char ** argv) +int main (int argc, char ** argv) { printf ("HOOKS TESTS\n"); printf ("=================\n\n"); init (argc, argv); test_getPluginConfigFromContract_withConfigInContract (); - test_getPluginConfigFromContract_withoutConfigInContract(); - test_loadPlugin(); - test_loadPlugin_inexistent(); - test_isGoptsEnabledByContract(true); - test_isGoptsEnabledByContract(false); - test_initHooks_shouldInitAllHooksWithoutFailure(); + test_getPluginConfigFromContract_withoutConfigInContract (); + test_loadPlugin (); + test_loadPlugin_inexistent (); + test_isGoptsEnabledByContract (true); + test_isGoptsEnabledByContract (false); + test_initHooks_shouldInitAllHooksWithoutFailure (); printf ("\ntest_hooks RESULTS: %d test(s) done. %d error(s).\n", nbTest, nbError); return nbError; } - - From 1dc497d22417db75f2315061b0473937e8860260 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 21 Sep 2022 15:27:40 +0000 Subject: [PATCH 35/38] Restyled by prettier-markdown --- doc/decisions/hooks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/decisions/hooks.md b/doc/decisions/hooks.md index 6e3e245656f..0ecdf996118 100644 --- a/doc/decisions/hooks.md +++ b/doc/decisions/hooks.md @@ -3,6 +3,7 @@ ## Problem In the current global plugins implementation: + - Notification does not happen once after final commit, but for every plugin - Problems in spec plugin From aa5af5355741ab92212c4d48a1b2b63ee69e8bde Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Thu, 22 Sep 2022 09:25:16 +0200 Subject: [PATCH 36/38] Update src/libs/elektra/kdb.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- src/libs/elektra/kdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/elektra/kdb.c b/src/libs/elektra/kdb.c index ad12358f73b..54ec9ec6eb9 100644 --- a/src/libs/elektra/kdb.c +++ b/src/libs/elektra/kdb.c @@ -1000,6 +1000,7 @@ KDB * kdbOpen (const KeySet * contract, Key * errorKey) } // TODO (atmaxinger): improve + // TODO: combine with ensureContract below if (initHooks (handle, elektraKs, handle->modules, contract, errorKey) == -1) { ELEKTRA_SET_INSTALLATION_ERROR (errorKey, "Initializing hooks failed. Please see warning of concrete plugin"); From a77523e6d33e612be18a3e8be5616e5fff9631eb Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Thu, 22 Sep 2022 09:25:22 +0200 Subject: [PATCH 37/38] Update doc/decisions/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/decisions/hooks.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/decisions/hooks.md b/doc/decisions/hooks.md index 0ecdf996118..512d28c14f5 100644 --- a/doc/decisions/hooks.md +++ b/doc/decisions/hooks.md @@ -2,7 +2,12 @@ ## Problem -In the current global plugins implementation: +Some components of `kdbGet`/`kdbSet` should be optional. +We use the plugin system for that. +However, some of these cases cannot be tied to a mountpoint. +This was the idea of global plugins, but that idea proved problematic. + +In the old global plugins implementation: - Notification does not happen once after final commit, but for every plugin From 56ff3b2e49783835b43ecac407a319fc45951f35 Mon Sep 17 00:00:00 2001 From: Maximilian Irlinger Date: Thu, 22 Sep 2022 09:26:48 +0200 Subject: [PATCH 38/38] Update doc/dev/hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Klemens Böswirth <23529132+kodebach@users.noreply.github.com> --- doc/dev/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/hooks.md b/doc/dev/hooks.md index ea93a15cb19..3891879754f 100644 --- a/doc/dev/hooks.md +++ b/doc/dev/hooks.md @@ -13,7 +13,7 @@ A symlink replacing the shared library file of the plugin could be used to chang If a plugin should be able to act upon a hook, it must export all the functions that the hook requires. These exports are of the form `system:/elektra/modules//exports/hook//`. -For example, the `gopts` hook only requires the `get` function. A plugin that wants to act as a `gopts` hook therefore has to export `system:/elektra/modules//exports/hook/gopts/get`. +For example, the `gopts` hook only requires the `get` function. A plugin that wants to act upon the `gopts` hook therefore has to export `system:/elektra/modules//exports/hook/gopts/get`. Other hooks (e.g. `spec`) require multiple exported functions.