Exemplo n.º 1
0
/**
 * @internal
 * Called whenever the socket becomes readable.
 * ZeroMq since sends multipart messages atomically (all or nothing)
 * both message parts are instantly available.
 *
 * @param socket  ZeroMq socket
 * @param context context passed to elektraIoAdapterZeroMqAttach()
 */
static void zeroMqRecvSocketReadable (void * socket, void * context)
{
	ElektraZeroMqRecvPluginData * data = context;

	char * changeType;
	char * changedKeyName;

	zmq_msg_t message;
	zmq_msg_init (&message);

	int result = zmq_msg_recv (&message, socket, ZMQ_DONTWAIT);
	if (result == -1)
	{
		ELEKTRA_LOG_WARNING ("receiving change type failed: %s; aborting", zmq_strerror (zmq_errno ()));
		zmq_msg_close (&message);
		return;
	}
	if (!zmq_msg_more (&message))
	{
		ELEKTRA_LOG_WARNING ("message has only one part; aborting");
		zmq_msg_close (&message);
		return;
	}
	int length = zmq_msg_size (&message);
	changeType = elektraStrNDup (zmq_msg_data (&message), length + 1);
	changeType[length] = '\0';
	ELEKTRA_LOG_DEBUG ("received change type %s", changeType);

	result = zmq_msg_recv (&message, socket, ZMQ_DONTWAIT);
	if (result == -1)
	{
		ELEKTRA_LOG_WARNING ("receiving key name failed: %s; aborting", zmq_strerror (zmq_errno ()));
		elektraFree (changeType);
		zmq_msg_close (&message);
		return;
	}
	length = zmq_msg_size (&message);
	changedKeyName = elektraStrNDup (zmq_msg_data (&message), length + 1);
	changedKeyName[length] = '\0';
	ELEKTRA_LOG_DEBUG ("received key name %s", changedKeyName);

	// notify about changes
	Key * changedKey = keyNew (changedKeyName, KEY_END);
	data->notificationCallback (changedKey, data->notificationContext);

	zmq_msg_close (&message);
	elektraFree (changeType);
	elektraFree (changedKeyName);
}
Exemplo n.º 2
0
/**
 * @internal
 * Unmount global plugin at run-time.
 *
 * Removes a plugin at all placements.
 * Undos `mountGlobalPlugin()`.
 *
 * @param  kdb    KDB handle
 * @param  plugin Plugin handle
 * @retval 0 on errors
 * @retval 1 on success
 */
static int unmountGlobalPlugin (KDB * kdb, Plugin * plugin)
{
	ELEKTRA_NOT_NULL (kdb);
	ELEKTRA_NOT_NULL (plugin);

	char * placementList = getPluginPlacementList (plugin);

	// Parse plament list (contains placements from README.md seperated by
	// whitespace)
	char * placement = strtok (placementList, " ");
	while (placement != NULL)
	{
		// Convert placement name to internal index
		int placementIndex = placementToPosition (placement);
		if (placementIndex == -1)
		{
			elektraFree (placementList);
			return 0;
		}

		if (kdb->globalPlugins[placementIndex][MAXONCE] == plugin)
		{
			// Remove from direct placement as global plugin
			kdb->globalPlugins[placementIndex][MAXONCE] = NULL;
		}
		else
		{
			Plugin * pluginAtPlacement = kdb->globalPlugins[placementIndex][MAXONCE];
			// Add plugin to list plugin
			if (strcmp (pluginAtPlacement->name, "list") == 0)
			{
				ELEKTRA_LOG_DEBUG (
					"required position %s/maxonce taken by list plugin, "
					"removing plugin",
					placement);
				int result = listRemovePlugin (pluginAtPlacement, plugin);
				if (!result)
				{
					ELEKTRA_LOG_WARNING ("could not remove plugin from list plugin at position %s/maxonce", placement);
					elektraFree (placementList);
					return 0;
				}
			}
			else
			{
				ELEKTRA_LOG_WARNING (
					"required position %s/maxonce taken by plugin %s, "
					"should be either list or plugin!",
					placement, pluginAtPlacement->name);
			}
		}

		// Process next placement in list
		placement = strtok (NULL, " ");
	}

	elektraFree (placementList);

	return 1;
}
Exemplo n.º 3
0
/**
 * @see ElektraNotificationOpenNotification (kdbnotificationinternal.h)
 */
void elektraZeroMqRecvOpenNotification (Plugin * handle, KeySet * parameters)
{
	ELEKTRA_NOT_NULL (handle);
	ElektraZeroMqRecvPluginData * pluginData = elektraPluginGetData (handle);
	ELEKTRA_NOT_NULL (pluginData);

	ElektraNotificationCallback callback;
	Key * callbackKey = ksLookupByName (parameters, "/callback", 0);
	ELEKTRA_NOT_NULL (callbackKey);
	callback = *(ElektraNotificationCallback *) keyValue (callbackKey);

	ElektraNotificationCallbackContext * context;
	Key * contextKey = ksLookupByName (parameters, "/context", 0);
	if (contextKey != NULL)
	{
		context = *(ElektraNotificationCallbackContext **) keyValue (contextKey);
	}
	else
	{
		context = NULL;
	}

	pluginData->notificationCallback = callback;
	pluginData->notificationContext = context;

	// init dbus connections
	if (pluginData->ioBinding)
	{
		elektraZeroMqRecvSetup (pluginData);
	}
	else
	{
		ELEKTRA_LOG_DEBUG ("no I/O binding present. plugin in noop mode");
	}
}
Exemplo n.º 4
0
/**
 * @internal
 * Global mount given plugin at run-time.
 *
 * Reads placements from the plugin directly inserts the plugin.
 * Also supports adding itself to the list plugin at run-time if present
 * at requested global placement.
 *
 * @param  kdb    KDB handle
 * @param  plugin Plugin handle
 * @retval 0 on errors
 * @retval 1 on success
 */
static int mountGlobalPlugin (KDB * kdb, Plugin * plugin)
{
	ELEKTRA_NOT_NULL (kdb);
	ELEKTRA_NOT_NULL (plugin);

	char * placementList = getPluginPlacementList (plugin);

	// Parse plament list (contains placements from README.md seperated by
	// whitespace)
	char * placement = strtok (placementList, " ");
	while (placement != NULL)
	{
		// Convert placement name to internal index
		int placementIndex = placementToPosition (placement);
		if (placementIndex == -1)
		{
			elektraFree (placementList);
			return 0;
		}

		if (kdb->globalPlugins[placementIndex][MAXONCE] == NULL)
		{
			// Insert directly as global plugin
			kdb->globalPlugins[placementIndex][MAXONCE] = plugin;
		}
		else
		{
			Plugin * pluginAtPlacement = kdb->globalPlugins[placementIndex][MAXONCE];
			// Add plugin to list plugin
			if (strcmp (pluginAtPlacement->name, "list") == 0)
			{
				ELEKTRA_LOG_DEBUG ("required position %s/maxonce taken by list plugin, adding plugin", placement);
				int result = listAddPlugin (pluginAtPlacement, plugin, placement);
				if (!result)
				{
					ELEKTRA_LOG_WARNING ("could not add plugin to list plugin at position %s/maxonce", placement);
					elektraFree (placementList);
					return 0;
				}
			}
			else
			{
				// cannot manually add list module here. configuration is broken:
				// the list module needs to be mounted in every position to keep track
				// of the current position
				ELEKTRA_LOG_WARNING ("required position %s/maxonce taken by plugin %s, aborting!", placement,
						     pluginAtPlacement->name);
				elektraFree (placementList);
				return 0;
			}
		}

		// Process next placement in list
		placement = strtok (NULL, " ");
	}

	elektraFree (placementList);

	return 1;
}
Exemplo n.º 5
0
/**
 * @brief Wrapper for open().
 *
 * @param parentKey containing the filename
 * @param flags file access mode
 * @param mode file mode bits when file is created
 *
 * @return file descriptor
 */
static int openFile (Key * parentKey, int flag, mode_t mode)
{
	int fd;
	ELEKTRA_LOG_DEBUG ("opening file %s", keyString (parentKey));

	if ((fd = open (keyString (parentKey), flag, mode)) == -1)
	{
		ELEKTRA_LOG_WARNING ("error opening file %s", keyString (parentKey));
	}
	return fd;
}
Exemplo n.º 6
0
/**
 * @brief This function walks a tree calling methods of the given listener.
 *
 * @param listener This argument specifies the listener which this function
 *                 uses to convert the tree to a key set.
 * @param root This variable stores the root of the tree this function
 *             visits.
 */
void walk (Listener & listener, node const & node)
{
	ELEKTRA_LOG_DEBUG ("Parse tree: %s", toString (node).c_str ());

	// If the document contains only one a single value we call `exitValue`
	// for that function. We need to handle that special case to not add
	// value multiple times for maps (once for `c_l_block_map_implicit_value`
	// and `c_l_block_seq_entry`) and once for the child of
	// `c_l_block_map_implicit_value`).
	if (node.is_root () && !node.children.empty () && ends_with (node.children.back ()->name (), "node"))
	{
		listener.exitValue (node.children.back ()->content ());
		return;
	}

	executeListenerMethods (listener, node);
}
Exemplo n.º 7
0
/** Initialize a plugin to be executed in its own process
 *
 * This will prepare all the required resources and then fork the current
 * process. After the initialization the child process will typically
 * call the command loop while the parent starts to send commands to it.
 * Also the resulting process information has to be stored for the plugin.
 * In order to allow users to handle custom plugin data this will not
 * automatically call elektraPluginSetData.
 *
 * Typically called in a plugin's open function like (assuming no custom plugin data):
 * @code
int elektraPluginOpen (Plugin * handle, Key * errorKey)
{
	ElektraPluginProcess * pp = elektraPluginGetData (handle);
	if (pp == NULL)
	{
		if ((pp = elektraPluginProcessInit (errorKey)) == NULL) return ELEKTRA_PLUGIN_STATUS_ERROR;
		elektraPluginSetData (handle, pp);
		if (!elektraPluginProcessIsParent (pp)) elektraPluginProcessStart (handle, pp);
	}
	if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessOpen (pp, errorKey);

	// actual plugin functionality to be executed in a child process
	return ELEKTRA_PLUGIN_STATUS_SUCCESS;
}
 * @endcode
 *
 * @param handle the plugin's handle
 * @param errorKey a key where error messages will be set
 * @retval NULL if the initialization failed
 * @retval a pointer to the information
 * @ingroup processplugin
 **/
ElektraPluginProcess * elektraPluginProcessInit (Key * errorKey)
{
	// First time initialization
	ElektraPluginProcess * pp;
	pp = elektraMalloc (sizeof (ElektraPluginProcess));
	pp->counter = 0;
	pp->pluginData = NULL;
	pp->parentCommandPipeKey = NULL;
	pp->parentPayloadPipeKey = NULL;
	pp->childCommandPipeKey = NULL;
	pp->childPayloadPipeKey = NULL;

	pp->dump = elektraInvokeOpen ("dump", 0, errorKey);
	if (!pp->dump)
	{
		cleanupPluginData (pp, errorKey, 0);
		ELEKTRA_SET_ERROR (190, errorKey, "Failed to initialize the dump plugin");
		return NULL;
	}

	// As generally recommended, ignore SIGPIPE because we will notice that the
	// commandKeySet has been transferred incorrectly anyway to detect broken pipes
	signal (SIGPIPE, SIG_IGN);

	// Prepare the pipes
	if (!makePipe (pp, errorKey, "parentCommandPipe", pp->parentCommandPipe) ||
	    !makePipe (pp, errorKey, "parentPayloadPipe", pp->parentPayloadPipe) ||
	    !makePipe (pp, errorKey, "childCommandPipe", pp->childCommandPipe) ||
	    !makePipe (pp, errorKey, "childPayloadPipe", pp->childPayloadPipe))
		return NULL;

	pp->pid = fork ();

	if (pp->pid < 0)
	{
		cleanupPluginData (pp, errorKey, 1);
		ELEKTRA_SET_ERRORF (190, errorKey, "Failed to fork the plugin process, fork () returned %d", pp->pid);
		return NULL;
	}

	int pipeIdx = elektraPluginProcessIsParent (pp);
	close (pp->parentCommandPipe[!pipeIdx]);
	close (pp->parentPayloadPipe[!pipeIdx]);
	close (pp->childCommandPipe[pipeIdx]);
	close (pp->childPayloadPipe[pipeIdx]);

	ELEKTRA_LOG_DEBUG ("parentCommandPipe[%d] has file descriptor %d", pipeIdx, pp->parentCommandPipe[pipeIdx]);
	ELEKTRA_LOG_DEBUG ("parentPayloadPipe[%d] has file descriptor %d", pipeIdx, pp->parentPayloadPipe[pipeIdx]);
	ELEKTRA_LOG_DEBUG ("childCommandPipe[%d] has file descriptor %d", !pipeIdx, pp->childCommandPipe[!pipeIdx]);
	ELEKTRA_LOG_DEBUG ("childPayloadPipe[%d] has file descriptor %d", !pipeIdx, pp->childPayloadPipe[!pipeIdx]);

	// Prepare the keys for the pipes to use with dump
	pp->parentCommandPipeKey = makePipeKey ("parentCommandPipe", pp->parentCommandPipe[pipeIdx]);
	pp->parentPayloadPipeKey = makePipeKey ("parentPayloadPipe", pp->parentPayloadPipe[pipeIdx]);
	pp->childCommandPipeKey = makePipeKey ("childCommandPipe", pp->childCommandPipe[!pipeIdx]);
	pp->childPayloadPipeKey = makePipeKey ("childPayloadPipe", pp->childPayloadPipe[!pipeIdx]);

	ELEKTRA_LOG_DEBUG ("parentCommandPipeKey is %s on %d", keyString (pp->parentCommandPipeKey), pp->pid);
	ELEKTRA_LOG_DEBUG ("parentPayloadPipeKey is %s on %d", keyString (pp->parentPayloadPipeKey), pp->pid);
	ELEKTRA_LOG_DEBUG ("childCommandPipeKey is %s on %d", keyString (pp->childCommandPipeKey), pp->pid);
	ELEKTRA_LOG_DEBUG ("childPayloadPipeKey is %s on %d", keyString (pp->childPayloadPipeKey), pp->pid);

	ELEKTRA_LOG_DEBUG ("The pluginprocess is set with the pid %d", pp->pid);
	return pp;
}
Exemplo n.º 8
0
/** Call a plugin's function in a child process
 *
 * This will wrap all the required information to execute the given
 * command in a keyset and send it over to the child process. Then
 * it waits for the child process's answer and copies the result
 * back into the original plugin keyset and plugin key.
 *
 * Typically called like
 * @code
int elektraPluginSet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	ElektraPluginProcess * pp = elektraPluginGetData (handle);
	if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessSend (pp, ELEKTRA_PLUGINPROCESS_SET, returned, parentKey);

	// actual plugin functionality to be executed in a child process
	return ELEKTRA_PLUGIN_STATUS_SUCCESS;
}
 * @endcode
 *
 * @param pp the data structure containing the plugin's process information
 * @param command the plugin command that should be executed, e.g. ELEKTRA_PLUGINPROCESS_GET
 * @param originalKeySet the original key set that the parent process receives
 * @param key the original key the parent process receives
 * @retval ELEKTRA_PLUGIN_STATUS_ERROR if the child process communication failed
 * @retval the called plugin's return value otherwise
 * @see elektraPluginProcessIsParent for checking if we are in the parent or child process
 * @ingroup processplugin
 **/
int elektraPluginProcessSend (const ElektraPluginProcess * pp, pluginprocess_t command, KeySet * originalKeySet, Key * key)
{
	// Ensure we have a keyset when trying to call GET SET and ERROR
	if ((command == ELEKTRA_PLUGINPROCESS_GET || command == ELEKTRA_PLUGINPROCESS_SET || command == ELEKTRA_PLUGINPROCESS_ERROR) &&
	    originalKeySet == NULL)
	{
		ELEKTRA_SET_ERROR (191, key,
				   "originalKeySet has to exist when calling GET SET and ERROR via pluginprocess; but it is NULL");
		return ELEKTRA_PLUGIN_STATUS_ERROR;
	}

	// Construct the command set that controls the pluginprocess communication
	KeySet * commandKeySet = ksNew (6, KS_END);
	ksAppendKey (commandKeySet, keyNew ("/pluginprocess/parent/name", KEY_VALUE, keyName (key), KEY_END));
	Key * parentKey = keyDup (key);
	keySetName (parentKey, "/pluginprocess/parent");
	ksAppendKey (commandKeySet, parentKey);
	char * commandStr = longToStr (command);
	ksAppendKey (commandKeySet, keyNew ("/pluginprocess/command", KEY_VALUE, commandStr, KEY_END));
	elektraFree (commandStr);
	ksAppendKey (commandKeySet, keyNew ("/pluginprocess/version", KEY_VALUE, "1", KEY_END));

	// Some plugin functions don't use keysets, in that case don't send any actual payload, signal via flag
	KeySet * keySet = originalKeySet != NULL ? ksDup (originalKeySet) : NULL;
	char * payloadSizeStr = longToStr (ksGetSize (originalKeySet));
	ksAppendKey (commandKeySet,
		     keyNew ("/pluginprocess/payload/size", KEY_VALUE, originalKeySet == NULL ? "-1" : payloadSizeStr, KEY_END));
	elektraFree (payloadSizeStr);

	// Serialize, currently statically use dump as our default format, this already writes everything out to the pipe
	ELEKTRA_LOG ("Parent: Sending data to issue command %u it through pipe %s", command, keyString (pp->parentCommandPipeKey));
	elektraInvoke2Args (pp->dump, "set", commandKeySet, pp->parentCommandPipeKey);
	if (keySet != NULL)
	{
		ELEKTRA_LOG ("Parent: Sending the payload keyset with %zd keys through the pipe %s", ksGetSize (keySet),
			     keyString (pp->parentPayloadPipeKey));
		elektraInvoke2Args (pp->dump, "set", keySet, pp->parentPayloadPipeKey);
	}

	// Deserialize
	ELEKTRA_LOG_DEBUG ("Parent: Waiting for the result now on pipe %s", keyString (pp->childCommandPipeKey));
	elektraInvoke2Args (pp->dump, "get", commandKeySet, pp->childCommandPipeKey);

	if (keySet != NULL)
	{
		// clear the keyset before to avoid memleaks caused by dump
		char * endPtr;
		int prevErrno = errno;
		errno = 0;
		long payloadSize =
			strtol (keyString (ksLookupByName (commandKeySet, "/pluginprocess/payload/size", KDB_O_NONE)), &endPtr, 10);
		// in case the payload size fails to be transferred, that it shouldn't, we simply assume the previous size
		if (*endPtr != '\0' || errno == ERANGE || payloadSize < 0) payloadSize = ksGetSize (keySet);
		errno = prevErrno;
		ksDel (keySet);
		keySet = ksNew (payloadSize, KS_END);
		elektraInvoke2Args (pp->dump, "get", keySet, pp->childPayloadPipeKey);
		ELEKTRA_LOG ("Parent: We received %zd keys in return", ksGetSize (keySet));
	}

	// Bring everything back in order by removing our process-related keys
	Key * parentDeserializedKey = ksLookupByName (commandKeySet, "/pluginprocess/parent", KDB_O_NONE);
	Key * resultKey = ksLookupByName (commandKeySet, "/pluginprocess/result", KDB_O_NONE);

	// Parse the result value
	char * endPtr;
	int prevErrno = errno;
	errno = 0;
	long lresult = strtol (keyString (resultKey), &endPtr, 10);
	if (*endPtr != '\0' || errno == ERANGE || lresult > INT_MAX || lresult < INT_MIN)
	{
		ELEKTRA_SET_ERRORF (191, key, "Received invalid return code or no KeySet: %s", keyString (resultKey));
		lresult = ELEKTRA_PLUGIN_STATUS_ERROR;
	}
	else // Copy everything back into the actual keysets
	{
		Key * parentKeyInOriginalKeySet = keySet != NULL ? ksLookup (originalKeySet, key, KDB_O_NONE) : NULL;
		// maybe there are just 2 keys with the same name, can happen in theory, so compare memory
		int parentKeyExistsInOriginalKeySet = parentKeyInOriginalKeySet == key;
		// if the child added the parent key to the keyset pop it from the keyset
		// then reinsert key after we copied the data and delete this serialized copy
		Key * parentKeyInKeySet = keySet != NULL ? ksLookup (keySet, key, KDB_O_POP) : NULL;
		int childAddedParentKey = parentKeyInKeySet != NULL;

		// Unfortunately we can't use keyCopy here as ksAppendKey locks it so it will fail
		// This is the case if the parent key is also contained in the originalKeySet / has been appended
		// As an invariant we assume plugins don't change the parent key's name during a plugin call
		// This would interfere with keyset memberships
		keySetString (key, keyString (parentDeserializedKey));

		// Clear metadata before, we allow children to modify it
		keyRewindMeta (key);
		const Key * currentMeta;
		while ((currentMeta = keyNextMeta (key)) != NULL)
		{
			keySetMeta (key, keyName (currentMeta), 0);
		}
		keyCopyAllMeta (key, parentDeserializedKey);
		if (childAddedParentKey) keyCopyAllMeta (key, parentKeyInKeySet);

		if (keySet != NULL)
		{
			// in case originalKeySet contains key this would make it stuck
			// thus remove it here and re-add it afterwards
			if (parentKeyExistsInOriginalKeySet) ksLookup (originalKeySet, parentKeyInOriginalKeySet, KDB_O_POP);
			ksCopy (originalKeySet, keySet);
			if (parentKeyExistsInOriginalKeySet || childAddedParentKey) ksAppendKey (originalKeySet, key);
			if (childAddedParentKey) keyDel (parentKeyInKeySet);
		}
	}
	errno = prevErrno;

	// Command finished, cleanup the remaining memory now
	ksDel (commandKeySet);
	if (keySet != NULL) ksDel (keySet);

	return lresult; // Safe, we had a bound check before, and plugins should return values in the int range
}
Exemplo n.º 9
0
/** Start the child process' command loop
 *
 * This will make the child process wait for plugin commands
 * and execute them, returning the result to the parent. This
 * is typically called in a plugin's open function.
 *
 * @param handle the plugin's handle
 * @param pp the data structure containing the plugin's process information
 * @see elektraPluginProcessInit how to use this function in a plugin
 * @ingroup processplugin
 **/
void elektraPluginProcessStart (Plugin * handle, ElektraPluginProcess * pp)
{
	int counter = 0;

	do
	{
		KeySet * commandKeySet = ksNew (6, KS_END);
		KeySet * keySet = NULL;
		ELEKTRA_LOG_DEBUG ("Child: Wait for commands on pipe %s", keyString (pp->parentCommandPipeKey));
		elektraInvoke2Args (pp->dump, "get", commandKeySet, pp->parentCommandPipeKey);

		if (ksGetSize (commandKeySet) == 0)
		{
			ELEKTRA_LOG_DEBUG ("Child: Failed to read from parentCommandPipe, exiting");
			ksDel (commandKeySet);
			break;
		}

		Key * payloadSizeKey = ksLookupByName (commandKeySet, "/pluginprocess/payload/size", KDB_O_NONE);
		char * endPtr;
		// We'll always write some int value into it, so this should be fine
		int prevErrno = errno;
		errno = 0;
		long payloadSize = strtol (keyString (payloadSizeKey), &endPtr, 10);
		// in case the payload size fails to be transferred, that it shouldn't, we can only assume no payload
		if (*endPtr == '\0' && errno != ERANGE && payloadSize >= 0)
		{
			keySet = ksNew (payloadSize, KS_END);
			elektraInvoke2Args (pp->dump, "get", keySet, pp->parentPayloadPipeKey);
			ELEKTRA_LOG_DEBUG ("Child: We received a KeySet with %zd keys in it", ksGetSize (keySet));
		}
		errno = prevErrno;

		Key * commandKey = ksLookupByName (commandKeySet, "/pluginprocess/command", KDB_O_NONE);
		Key * parentNameKey = ksLookupByName (commandKeySet, "/pluginprocess/parent/name", KDB_O_NONE);
		Key * parentKey = ksLookupByName (commandKeySet, "/pluginprocess/parent", KDB_O_POP);
		Key * key = keyDup (parentKey);
		keySetName (key, keyString (parentNameKey));
		int result = ELEKTRA_PLUGIN_STATUS_ERROR;

		// We'll always write some int value into it, so this should be fine
		prevErrno = errno;
		errno = 0;
		long command = strtol (keyString (commandKey), &endPtr, 10);
		if (*endPtr == '\0' && errno != ERANGE)
		{
			ELEKTRA_LOG ("Child: We want to execute the command with the value %ld now", command);
			// Its hard to figure out the enum size in a portable way but for this comparison it should be ok
			switch (command)
			{
			case ELEKTRA_PLUGINPROCESS_OPEN:
				counter++;
				result = handle->kdbOpen (handle, key);
				break;
			case ELEKTRA_PLUGINPROCESS_CLOSE:
				counter--;
				result = handle->kdbClose (handle, key);
				break;
			case ELEKTRA_PLUGINPROCESS_GET:
				result = handle->kdbGet (handle, keySet, key);
				break;
			case ELEKTRA_PLUGINPROCESS_SET:
				result = handle->kdbSet (handle, keySet, key);
				break;
			case ELEKTRA_PLUGINPROCESS_ERROR:
				result = handle->kdbError (handle, keySet, key);
				break;
			default:
				result = ELEKTRA_PLUGIN_STATUS_ERROR;
			}
			ELEKTRA_LOG_DEBUG ("Child: Command executed with return value %d", result);
		}
		else
		{
			ELEKTRA_LOG_DEBUG ("Child: Unrecognized command %s", keyString (commandKey));
			ELEKTRA_SET_ERRORF (191, key, "Received invalid command code or no KeySet: %s", keyString (commandKey));
		}
		errno = prevErrno;
		char * resultStr = longToStr (result);
		ksAppendKey (commandKeySet, keyNew ("/pluginprocess/result", KEY_VALUE, resultStr, KEY_END));
		elektraFree (resultStr);
		keySetName (key, "/pluginprocess/parent");
		ksAppendKey (commandKeySet, key);
		keyDel (parentKey);

		ELEKTRA_LOG_DEBUG ("Child: Writing the results back to the parent");
		elektraInvoke2Args (pp->dump, "set", commandKeySet, pp->childCommandPipeKey);
		if (keySet != NULL)
		{
			char * resultPayloadSize = longToStr (ksGetSize (keySet));
			keySetString (payloadSizeKey, resultPayloadSize);
			elektraFree (resultPayloadSize);
			elektraInvoke2Args (pp->dump, "set", keySet, pp->childPayloadPipeKey);
			ksDel (keySet);
		}
		ksDel (commandKeySet);
		ELEKTRA_LOG ("Child: Command handled, startup counter is at %d", counter);
	} while (counter);

	// Final Cleanup
	ELEKTRA_LOG_DEBUG ("Child: All done, exiting the child process now");
	cleanupPluginData (pp, 0, 1);
	// All done, exit the child process so it won't do any actual effects in elektra
	_Exit (EXIT_SUCCESS);
}
Exemplo n.º 10
0
/**
 * Updates all KeyRegistrations according to data from the given KeySet
 * @internal
 *
 * @param plugin    internal plugin handle
 * @param keySet    key set retrieved from hooks
 *                  e.g. elektraInternalnotificationGet or elektraInternalnotificationSet)
 *
 */
void elektraInternalnotificationUpdateRegisteredKeys (Plugin * plugin, KeySet * keySet)
{
	PluginState * pluginState = elektraPluginGetData (plugin);
	ELEKTRA_ASSERT (pluginState != NULL, "plugin state was not initialized properly");

	KeyRegistration * registeredKey = pluginState->head;
	while (registeredKey != NULL)
	{
		int changed = 0;
		Key * key;
		if (registeredKey->sameOrBelow)
		{
			Key * checkKey = keyNew (registeredKey->name, KEY_END);
			if (keySetContainsSameOrBelow (checkKey, keySet))
			{
				changed = 1;
				key = checkKey;
			}
			else
			{
				keyDel (checkKey);
			}
		}
		else
		{
			key = ksLookupByName (keySet, registeredKey->name, 0);
			if (key != NULL)
			{
				// Detect changes for string keys
				if (!keyIsString (key))
				{
					// always notify for binary keys
					changed = 1;
				}
				else
				{
					const char * currentValue = keyString (key);
					changed = registeredKey->lastValue == NULL || strcmp (currentValue, registeredKey->lastValue) != 0;

					if (changed)
					{
						// Save last value
						char * buffer = elektraStrDup (currentValue);
						if (buffer)
						{
							if (registeredKey->lastValue != NULL)
							{
								// Free previous value
								elektraFree (registeredKey->lastValue);
							}
							registeredKey->lastValue = buffer;
						}
					}
				}
			}
		}

		if (changed)
		{
			ELEKTRA_LOG_DEBUG ("found changed registeredKey=%s with string value \"%s\". using context or variable=%p",
					   registeredKey->name, keyString (key), registeredKey->context);

			// Invoke callback
			ElektraNotificationChangeCallback callback = *(ElektraNotificationChangeCallback) registeredKey->callback;
			callback (key, registeredKey->context);
			if (registeredKey->sameOrBelow)
			{
				keyDel (key);
			}
		}

		// proceed with next registered key
		registeredKey = registeredKey->next;
	}
}
Exemplo n.º 11
0
/* See documentation in header file. */
int ini_parse_file (FILE * file, const struct IniConfig * config, void * user)
{
	/* Uses a fair bit of stack (use heap instead if you need to) */
	char * line;

	char section[MAX_SECTION] = "";
	char prev_name[MAX_NAME] = "";

	char * start;
	char * end;
	char * name;
	char * value;
	char delim = config->delim;
	int lineno = 0;
	int error = 0;

	line = (char *)malloc (INI_MAX_LINE);

	ELEKTRA_LOG_DEBUG ("Allocated memory for line");

	if (!line)
	{
		return -2;
	}

	/* Scan through file line by line */
	while (fgets (line, INI_MAX_LINE, file) != NULL)
	{
		lineno++;
		ELEKTRA_LOG_DEBUG ("Read line %d with content “%s”", lineno, line);

		start = line;
#if INI_ALLOW_BOM
		if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB && (unsigned char)start[2] == 0xBF)
		{
			start += 3;
			config->bomHandler (user, 1);
		}
		else
		{
			config->bomHandler (user, 0);
		}
#endif
		if (*start == '\n')
		{
			if (!config->commentHandler (user, "") && !error) error = lineno;
			continue;
		}
		start = lskip (line);
		if (*start == '\0')
		{
			if (!config->commentHandler (user, "") && !error) error = lineno;
			continue;
		}
		if (isContinuation (line, config) && config->supportMultiline && *prev_name)
		{
			start = line + strlen (config->continuationString);
			if (*start == '"') ++start;
			end = line + (strlen (line) - 1);
			while ((*end != '"') && (!isprint (*end)) && (end > start))
			{
				if (*end == '\n') *end = '\0';
				--end;
			}
			if (*end == '"') *end = '\0';

			if (!config->keyHandler (user, section, prev_name, start, 1) && !error) error = lineno;
		}
		else if (isSection (line))
		{
			ELEKTRA_LOG_DEBUG ("Line contains a section");
			end = line + (strlen (line) - 1);
			while (end > start)
			{
				if (*end == ']') break;
				--end;
			}
			++start;
			if (*end == ']')
			{
				*end = '\0';
				strncpy0 (section, start, sizeof (section));
				*prev_name = '\0';
				ELEKTRA_LOG_DEBUG ("Found section “%s”", section);

				size_t numberBackslashes = 0;
				for (char * endSection = section + strlen (section) - 1; endSection >= section && *endSection == '\\';
				     endSection--)
				{
					numberBackslashes++;
				}
				if (numberBackslashes % 2 != 0)
				{
					ELEKTRA_LOG_WARNING ("Found uneven number of backlashes at end of section");
					error = lineno;
					break;
				}

				if (!config->sectionHandler (user, section) && !error) error = lineno;
			}
			else
			{
				end = line + (strlen (line) - 1);
				if (*end == '\n')
				{
					strncpy0 (section, start, sizeof (section));
					while (fgets (line, INI_MAX_LINE, file))
					{
						end = line + (strlen (line) - 1);
						while ((end > line) && *end != ']')
							--end;
						if (*end == ']')
						{
							*end = '\0';
							strncpy0 (section + strlen (section), line, sizeof (section) - strlen (section));
							*prev_name = '\0';
							if (!config->sectionHandler (user, section) && !error) error = lineno;
							break;
						}
						else
						{
							strncpy0 (section + strlen (section), line, sizeof (section) - strlen (section));
						}
					}
				}
				else
				{
					error = lineno;
				}
			}
		}
		else if (isComment (line))
		{
			start = line;
			end = line + (strlen (line) - 1);
			if (*end == '\n') *end = '\0';
			if (!config->commentHandler (user, start) && !error) error = lineno;
		}
		else
		{
			ELEKTRA_LOG_DEBUG ("Line contains a key");

			char * ptr = start;
			unsigned int assign = 0;
			ELEKTRA_LOG_DEBUG ("Search for delimiter “%c”", delim);
			while (*ptr)
			{
				if (*ptr == delim)
				{
					++assign;
				}
				++ptr;
			}

			if (assign == 1)
			{
				ELEKTRA_LOG_DEBUG ("Found exactly one delimiter");
				name = start;
				end = strchr (start, delim);
				if (*name == '"')
				{
					ELEKTRA_LOG_DEBUG ("Name starts with double quote character");
					++name;
					if (*(end - 2) == '"')
					{
						*(end - 2) = '\0';
					}
					else if (*(end - 1) == '"')
					{
						*(end - 1) = '\0';
					}
					else
					{
						ELEKTRA_LOG_DEBUG ("Did not find closing double quote characters in current line");
						strncpy0 (prev_name, name, sizeof (prev_name));
						while (fgets (line, INI_MAX_LINE, file))
						{
							ELEKTRA_LOG_DEBUG ("Read continuation line with content “%s”", line);
							end = line + (strlen (line) - 1);
							while (end > line && *end != '"')
								--end;
							if (*end == '"')
							{
								ELEKTRA_LOG_DEBUG ("Found closing double quote character");
								*(end++) = '\0';
								strncpy0 (prev_name + strlen (prev_name), line,
									  sizeof (prev_name) - strlen (prev_name));
								break;
							}
							else
							{
								ELEKTRA_LOG_DEBUG ("Found name continuation");
								strncpy (prev_name + strlen (prev_name), line,
									 sizeof (prev_name) - strlen (prev_name));
							}
							ELEKTRA_LOG_DEBUG ("New extended name is “%s”", prev_name);
						}
						name = prev_name;
						ELEKTRA_LOG_DEBUG ("Name of key is “%s”", name);
					}
				}
				if (*end != delim)
				{
					ELEKTRA_LOG_DEBUG ("Search for delimiter in “%s”", end);
					ptr = lskip (end + 1);
					end = strchr (ptr, delim);
					if (end && *end == delim)
					{
						*end = '\0';
						ELEKTRA_LOG_DEBUG ("Found delimiter – New name is “%s”", end);
					}
					else
					{
						ELEKTRA_LOG_WARNING ("Unable to find delimiter");
						error = lineno;
						break;
					}
				}
				else
				{
					*end = '\0';
				}
				if (name != prev_name && end > line)
				{
					rstrip (end - 1);
				}
				value = lskip (end + 1);
				end = find_char_or_comment (value, '\0');
				if (*end == ';') *end = '\0';
				rstrip (value);
				if (*value == '"')
				{
					*(value++) = '\0';
					while ((*end != '"') && !isprint (*end) && end > value)
						--end;
					if (*end == '"') *end = '\0';
				}
				if (prev_name != name) strncpy0 (prev_name, name, sizeof (prev_name));
				if (!config->keyHandler (user, section, name, value, 0) && !error) error = lineno;
			}
			else if (assign == 0)
			{
				ELEKTRA_LOG_DEBUG ("Found no delimiter");
				if (*start == '"')
				{
					ELEKTRA_LOG_DEBUG ("Found initial double quote character");
					++start;
					end = line + (strlen (line) - 1);
					while (end > start && *end != '"')
						--end;
					if (*end == '"' && end != start)
					{
						*end = '\0';
						if (!config->keyHandler (user, section, start, NULL, 0) && !error) error = lineno;
					}
					else
					{
						ELEKTRA_LOG_DEBUG ("Did not find closing double quote character");
						strncpy0 (prev_name, start, sizeof (prev_name));
						while (fgets (line, INI_MAX_LINE, file))
						{
							end = line + (strlen (line) - 1);
							ELEKTRA_LOG_DEBUG ("Read continuation line with content “%s”", line);
							while (end > line && *end != '"')
								--end;
							if (*end == '"')
							{
								ELEKTRA_LOG_DEBUG ("Found closing double quote character");
								*end = '\0';
								strncpy0 (prev_name + strlen (prev_name), line,
									  sizeof (prev_name) - strlen (prev_name));
								break;
							}
							else
							{
								ELEKTRA_LOG_DEBUG ("Found name continuation");
								strncpy (prev_name + strlen (prev_name), line,
									 sizeof (prev_name) - strlen (prev_name));
							}
							ELEKTRA_LOG_DEBUG ("New extended name is “%s”", prev_name);
						}
						name = prev_name;
						ptr = end + 1;
						end = strchr (ptr, '=');
						if (!end) end = strchr (ptr, ':');
						if (!end)
						{
							if (!config->keyHandler (user, section, name, NULL, 0) && !error) error = lineno;
						}
						else
						{
							*end = '\0';
							value = lskip (end + 1);
							if (*value == '"') end = find_char_or_comment (value, '\0');
							if (*end == ';') *end = '\0';
							rstrip (value);
							if (*value == '"' || *(value + 1) == '"')
							{
								if (*value == '"')
									*(value++) = '\0';
								else if (*(value + 1) == '"')
								{
									*(value + 1) = '\0';
									value += 2;
								}
								while ((*end != '"') && !isprint (*end) && end > value)
									--end;
								if (*end == '"') *end = '\0';
							}
							if (prev_name != name) strncpy0 (prev_name, name, sizeof (prev_name));
							if (!config->keyHandler (user, section, name, value, 0) && !error) error = lineno;
						}
					}
				}
				else
				{
					name = rstrip (start);
					strncpy0 (prev_name, name, sizeof (prev_name));
					if (!config->keyHandler (user, section, name, NULL, 0) && !error) error = lineno;
				}
			}
			else
			{
				ELEKTRA_LOG_DEBUG ("Found multiple delimiters");
				ptr = start + 1;
				while (*ptr)
				{
					if (*ptr == delim)
					{
						if (*(ptr + 1) == '"' || *(ptr + 2) == '"' || *(ptr - 1) == '"' || *(ptr - 2) == '"') break;
					}
					++ptr;
				}
				if (*ptr)
				{
					ELEKTRA_LOG_DEBUG ("Found double quote character");
					char tmpDel[4] = { ' ', delim, ' ', '\0' };
					end = strstr (ptr, tmpDel);
					name = NULL;
					if (end)
					{
						// keyname == "=" or " = " where '=' is the delimiter
						if (*(ptr + 1) == '"')
						{
							*(ptr + 1) = '\0';
						}
						else if (*(ptr + 2) == '"')
						{
							*(ptr + 2) = '\0';
						}
						if (*(ptr - 1) == '"')
							*(ptr - 1) = '\0';
						else if (*(ptr - 2) == '"')
							*(ptr - 2) = '\0';
						name = ptr;
					}
					else if (*ptr == delim)
					{
						*ptr = '\0';
						rstrip (start);
						if (*start == '"') ++start;
						if (*(ptr - 1) == '"')
							*(ptr - 1) = '\0';
						else if (*(ptr - 2) == '"')
							*(ptr - 2) = '\0';
						name = start;
					}
					else
					{
						if (!end) end = strrstr (start + 1, tmpDel);
						*end = '\0';
						ptr = end + 2;
						rstrip (start);
						name = start;
					}
					value = ptr + 1;

					end = find_char_or_comment (value, '\0');
					if (*end == ';') *end = '\0';
					rstrip (value);
					if (*value == '"' || *(value + 1) == '"')
					{
						if (*value == '"')
							*(value++) = '\0';
						else if (*(value + 1) == '"')
						{
							*(value + 1) = '\0';
							value += 2;
						}
						while ((*end != '"') && !isprint (*end) && end > value)
							--end;
						if (*end == '"') *end = '\0';
					}
				}
				else
				{
					ELEKTRA_LOG_DEBUG ("Found no double quote character");
					rstrip (start);
					name = start;
					end = strchr (start, delim);
					if (!end)
					{
						ELEKTRA_LOG_DEBUG ("Found no delimiter");
						value = NULL;
					}
					else
					{
						ELEKTRA_LOG_DEBUG ("Found delimiter");
						if (*end == delim) *end = '\0';
						rstrip (end - 1);
						value = lskip (end + 1);
						rstrip (value);
						if (*value == '"')
						{
							*(value++) = '\0';
							while ((*end != '"') && !isprint (*end) && end > value)
								--end;
							if (*end == '"') *end = '\0';
						}
					}
				}
				strncpy0 (prev_name, name, sizeof (prev_name));

				if (!config->keyHandler (user, section, name, value, 0) && !error) error = lineno;
			}
		}

#if INI_STOP_ON_FIRST_ERROR
		if (error) break;
#endif
	}

	free (line);
	return error;
}
Exemplo n.º 12
0
int elektraSimpleiniGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/simpleini"))
	{
		KeySet * moduleConfig = ksNew (
			30, keyNew ("system/elektra/modules/simpleini", KEY_VALUE, "simpleini plugin waits for your orders", KEY_END),
			keyNew ("system/elektra/modules/simpleini/exports", KEY_END),
			keyNew ("system/elektra/modules/simpleini/exports/get", KEY_FUNC, elektraSimpleiniGet, KEY_END),
			keyNew ("system/elektra/modules/simpleini/exports/set", KEY_FUNC, elektraSimpleiniSet, KEY_END),
#include "readme_simpleini.c"
			keyNew ("system/elektra/modules/simpleini/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
			keyNew ("system/elektra/modules/simpleini/config/needs", KEY_VALUE, "the needed configuration to work in a backend",
				KEY_END),
			keyNew ("system/elektra/modules/simpleini/config/needs/chars", KEY_VALUE, "Characters needed", KEY_END),
			// space in value now works:
			// TODO: characters present in format should be escaped
			/*
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/20", KEY_VALUE, "61", KEY_END), // space -> a
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/23", KEY_VALUE, "62", KEY_END), // # -> b
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/25", KEY_VALUE, "63",
				KEY_END), // % -> c (escape character)
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/3B", KEY_VALUE, "64", KEY_END), // ; -> d
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/3D", KEY_VALUE, "65", KEY_END), // = -> e
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/5C", KEY_VALUE, "66", KEY_END), // \\ -> f
			*/
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/0A", KEY_VALUE, "67", KEY_END), // enter (NL) -> g
			keyNew ("system/elektra/modules/simpleini/config/needs/chars/0D", KEY_VALUE, "68", KEY_END), // CR -> h
			keyNew ("system/elektra/modules/simpleini/config/needs/escape", KEY_VALUE, "25", KEY_END), KS_END);
		ksAppend (returned, moduleConfig);
		ksDel (moduleConfig);
		return 1;
	}

	char * key = 0;
	char * value = 0;
	int errnosave = errno;
	FILE * fp = fopen (keyString (parentKey), "r");
	if (!fp)
	{
		ELEKTRA_SET_ERROR_GET (parentKey);
		errno = errnosave;
		return -1;
	}

	char * format = getFormat (handle, "%ms", "%m[^\n]");

	ELEKTRA_LOG ("Read from '%s' with format '%s'", keyString (parentKey), format);

	int n = 0;
	size_t size = 0;
	ssize_t ksize = 0;
#pragma GCC diagnostic ignored "-Wformat"
	// icc warning #269: invalid format string conversion
	while ((n = fscanf (fp, format, &key, &value)) >= 0)
	{
		ELEKTRA_LOG_DEBUG ("Read %d parts: '%s' with value '%s'", n, key, value);
		if (n == 0)
		{
			// discard line
			getline (&key, &size, fp);
			ELEKTRA_LOG_DEBUG ("Discard '%s'", key);
			elektraFree (key);
			key = 0;
			continue;
		}

		Key * read = keyNew (keyName (parentKey), KEY_END);

		if (keyAddName (read, key) == -1)
		{
			ELEKTRA_ADD_WARNING (ELEKTRA_WARNING_INVALID_KEY, parentKey, key);
			keyDel (read);
			continue;
		}

		if (n == 2)
		{
			keySetString (read, value);
			elektraFree (value);
			value = 0;
		}

		if (ksAppendKey (returned, read) != ksize + 1)
		{
			ELEKTRA_SET_ERROR (ELEKTRA_ERROR_NOEOF, parentKey, "duplicated key");
			return -1;
		}
		++ksize;
		elektraFree (key);
		key = 0;
	}

	if (feof (fp) == 0)
	{
		elektraFree (format);
		fclose (fp);
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_NOEOF, parentKey, "not at the end of file");
		return -1;
	}

	elektraFree (format);
	fclose (fp);

	return 1; /* success */
}
Exemplo n.º 13
0
/**
 * @brief Opens the session with the Key database.
 *
 * @pre errorKey must be a valid key, e.g. created with keyNew()
 *
 * The method will bootstrap itself the following way.
 * The first step is to open the default backend. With it
 * system/elektra/mountpoints will be loaded and all needed
 * libraries and mountpoints will be determined.
 * These libraries for backends will be loaded and with it the
 * @p KDB data structure will be initialized.
 *
 * You must always call this method before retrieving or committing any
 * keys to the database. In the end of the program,
 * after using the key database, you must not forget to kdbClose().
 *
 * The pointer to the @p KDB structure returned will be initialized
 * like described above, and it must be passed along on any kdb*()
 * method your application calls.
 *
 * Get a @p KDB handle for every thread using elektra. Don't share the
 * handle across threads, and also not the pointer accessing it:
 *
 * @snippet kdbopen.c open
 *
 * You don't need kdbOpen() if you only want to
 * manipulate plain in-memory Key or KeySet objects.
 *
 * @pre errorKey must be a valid key, e.g. created with keyNew()
 *
 * @param errorKey the key which holds errors and warnings which were issued
 * @see kdbGet(), kdbClose() to end all affairs to the key database.
 * @retval handle on success
 * @retval NULL on failure
 * @ingroup kdb
 */
KDB * kdbOpen (Key * errorKey)
{
	if (!errorKey)
	{
		ELEKTRA_LOG ("no error key passed");
		return 0;
	}

	ELEKTRA_LOG ("called with %s", keyName (errorKey));

	int errnosave = errno;
	KDB * handle = elektraCalloc (sizeof (struct _KDB));
	Key * initialParent = keyDup (errorKey);

	handle->modules = ksNew (0, KS_END);
	if (elektraModulesInit (handle->modules, errorKey) == -1)
	{
		ksDel (handle->modules);
		elektraFree (handle);
		ELEKTRA_SET_ERROR (94, errorKey, "elektraModulesInit returned with -1");

		keySetName (errorKey, keyName (initialParent));
		keySetString (errorKey, keyString (initialParent));
		keyDel (initialParent);
		errno = errnosave;
		return 0;
	}

	KeySet * keys = ksNew (0, KS_END);
	int inFallback = 0;
	switch (elektraOpenBootstrap (handle, keys, errorKey))
	{
	case -1:
		ksDel (handle->modules);
		elektraFree (handle);
		ELEKTRA_SET_ERROR (40, errorKey, "could not open default backend");

		keySetName (errorKey, keyName (initialParent));
		keySetString (errorKey, keyString (initialParent));
		keyDel (initialParent);
		errno = errnosave;
		return 0;
	case 0:
		ELEKTRA_ADD_WARNING (17, errorKey,
				     "Initial kdbGet() failed, you should either fix " KDB_DB_INIT " or the fallback " KDB_DB_FILE);
		break;
	case 2:
		ELEKTRA_LOG ("entered fallback code for bootstrapping");
		inFallback = 1;
		break;
	}

	keySetString (errorKey, "kdbOpen(): mountGlobals");

	if (mountGlobals (handle, ksDup (keys), handle->modules, errorKey) == -1)
	{
		// mountGlobals also sets a warning containing the name of the plugin that failed to load
		ELEKTRA_ADD_WARNING (139, errorKey, "Mounting global plugins failed");
	}

	keySetName (errorKey, keyName (initialParent));
	keySetString (errorKey, "kdbOpen(): backendClose");

	backendClose (handle->defaultBackend, errorKey);
	splitDel (handle->split);
	handle->defaultBackend = 0;
	handle->trie = 0;

#ifdef HAVE_LOGGER
	if (inFallback) ELEKTRA_LOG_WARNING ("fallback for bootstrapping: you might want to run `kdb upgrade-bootstrap`");

	Key * key;

	ksRewind (keys);
	for (key = ksNext (keys); key; key = ksNext (keys))
	{
		ELEKTRA_LOG_DEBUG ("config for createTrie name: %s value: %s", keyName (key), keyString (key));
	}
#endif

	handle->split = splitNew ();

	keySetString (errorKey, "kdbOpen(): mountOpen");
	// Open the trie, keys will be deleted within mountOpen
	if (mountOpen (handle, keys, handle->modules, errorKey) == -1)
	{
		ELEKTRA_ADD_WARNING (93, errorKey, "Initial loading of trie did not work");
	}

	keySetString (errorKey, "kdbOpen(): mountDefault");
	if (mountDefault (handle, handle->modules, inFallback, errorKey) == -1)
	{
		ELEKTRA_SET_ERROR (40, errorKey, "could not reopen and mount default backend");
		keySetString (errorKey, "kdbOpen(): close");
		kdbClose (handle, errorKey);

		keySetName (errorKey, keyName (initialParent));
		keySetString (errorKey, keyString (initialParent));
		keyDel (initialParent);
		errno = errnosave;
		return 0;
	}

	keySetString (errorKey, "kdbOpen(): mountVersion");
	mountVersion (handle, errorKey);

	keySetString (errorKey, "kdbOpen(): mountModules");
	if (mountModules (handle, handle->modules, errorKey) == -1)
	{
		ELEKTRA_ADD_WARNING (92, errorKey, "Mounting modules did not work");
	}

	keySetName (errorKey, keyName (initialParent));
	keySetString (errorKey, keyString (initialParent));
	keyDel (initialParent);
	errno = errnosave;
	return handle;
}