示例#1
0
文件: kdb.c 项目: KurtMi/libelektra
/**
 * @brief Bootstrap, first phase with fallback
 * @internal
 *
 * @param handle already allocated, but without defaultBackend
 * @param [out] keys for bootstrapping
 * @param errorKey key to add errors too
 *
 * @retval -1 failure: cannot initialize defaultBackend
 * @retval 0 warning: could not get initial config
 * @retval 1 success
 * @retval 2 success in fallback mode
 */
int elektraOpenBootstrap (KDB * handle, KeySet * keys, Key * errorKey)
{
	handle->defaultBackend = backendOpenDefault (handle->modules, KDB_DB_INIT, errorKey);
	if (!handle->defaultBackend) return -1;

	handle->split = splitNew ();
	splitAppend (handle->split, handle->defaultBackend, keyNew (KDB_SYSTEM_ELEKTRA, KEY_END), 2);

	keySetName (errorKey, KDB_SYSTEM_ELEKTRA);
	keySetString (errorKey, "kdbOpen(): get");

	int funret = 1;
	int ret = kdbGet (handle, keys, errorKey);
	int fallbackret = 0;
	if (ret == 0 || ret == -1)
	{
		// could not get KDB_DB_INIT, try KDB_DB_FILE
		// first cleanup:
		ksClear (keys);
		backendClose (handle->defaultBackend, errorKey);
		splitDel (handle->split);

		// then create new setup:
		handle->defaultBackend = backendOpenDefault (handle->modules, KDB_DB_FILE, errorKey);
		if (!handle->defaultBackend)
		{
			elektraRemoveMetaData (errorKey, "error"); // fix errors from kdbGet()
			return -1;
		}
		handle->split = splitNew ();
		splitAppend (handle->split, handle->defaultBackend, keyNew (KDB_SYSTEM_ELEKTRA, KEY_END), 2);

		keySetName (errorKey, KDB_SYSTEM_ELEKTRA);
		keySetString (errorKey, "kdbOpen(): get fallback");
		fallbackret = kdbGet (handle, keys, errorKey);
		keySetName (errorKey, "system/elektra/mountpoints");

		KeySet * cutKeys = ksCut (keys, errorKey);
		if (fallbackret == 1 && ksGetSize (cutKeys) != 0)
		{
			funret = 2;
		}
		ksAppend (keys, cutKeys);
		ksDel (cutKeys);
	}

	if (ret == -1 && fallbackret == -1)
	{
		funret = 0;
	}

	elektraRemoveMetaData (errorKey, "error"); // fix errors from kdbGet()
	return funret;
}
KDB * kdb_new ()
{
	KDB * kdb = elektraCalloc (sizeof (KDB));
	kdb->split = splitNew ();
	return kdb;
}
示例#3
0
文件: kdb.c 项目: KurtMi/libelektra
/**
 * @brief Retrieve keys in an atomic and universal way.
 *
 * @pre The @p handle must be passed as returned from kdbOpen().
 *
 * @pre The @p returned KeySet must be a valid KeySet, e.g. constructed
 *     with ksNew().
 *
 * @pre The @p parentKey Key must be a valid Key, e.g. constructed with
 *     keyNew().
 *
 * If you pass NULL on any parameter kdbGet() will fail immediately without doing anything.
 *
 * The @p returned KeySet may already contain some keys, e.g. from previous
 * kdbGet() calls. The new retrieved keys will be appended using
 * ksAppendKey().
 *
 * If not done earlier kdbGet() will fully retrieve all keys under the @p parentKey
 * folder recursively (See Optimization below when it will not be done).
 *
 * @note kdbGet() might retrieve more keys than requested (that are not
 *     below parentKey). These keys must be passed to calls of kdbSet(),
 *     otherwise they will be lost. This stems from the fact that the
 *     user has the only copy of the whole configuration and backends
 *     only write configuration that was passed to them.
 *     For example, if you kdbGet() "system/mountpoint/interest"
 *     you will not only get all keys below system/mountpoint/interest,
 *     but also all keys below system/mountpoint (if system/mountpoint
 *     is a mountpoint as the name suggests, but
 *     system/mountpoint/interest is not a mountpoint).
 *     Make sure to not touch or remove keys outside the keys of interest,
 *     because others may need them!
 *
 * @par Example:
 * This example demonstrates the typical usecase within an application
 * (without error handling).
 *
 * @include kdbget.c
 *
 * When a backend fails kdbGet() will return -1 with all
 * error and warning information in the @p parentKey.
 * The parameter @p returned will not be changed.
 *
 * @par Optimization:
 * In the first run of kdbGet all requested (or more) keys are retrieved. On subsequent
 * calls only the keys are retrieved where something was changed
 * inside the key database. The other keys stay in the
 * KeySet returned as passed.
 *
 * It is your responsibility to save the original keyset if you
 * need it afterwards.
 *
 * If you want to be sure to get a fresh keyset again, you need to open a
 * second handle to the key database using kdbOpen().
 *
 * @param handle contains internal information of @link kdbOpen() opened @endlink key database
 * @param parentKey is used to add warnings and set an error
 *         information. Additionally, its name is a hint which keys
 *         should be retrieved (it is possible that more are retrieved, see Note above).
 *           - cascading keys (starting with /) will retrieve the same path in all namespaces
 *           - / will retrieve all keys
 * @param ks the (pre-initialized) KeySet returned with all keys found
 * 	will not be changed on error or if no update is required
 * @see ksLookup(), ksLookupByName() for powerful
 * 	lookups after the KeySet was retrieved
 * @see kdbOpen() which needs to be called before
 * @see kdbSet() to save the configuration afterwards and kdbClose() to
 * 	finish affairs with the key database.
 * @retval 1 if the keys were retrieved successfully
 * @retval 0 if there was no update - no changes are made to the keyset then
 * @retval -1 on failure - no changes are made to the keyset then
 * @ingroup kdb
 */
int kdbGet (KDB * handle, KeySet * ks, Key * parentKey)
{
	elektraNamespace ns = keyGetNamespace (parentKey);
	if (ns == KEY_NS_NONE)
	{
		return -1;
	}

	Key * oldError = keyNew (keyName (parentKey), KEY_END);
	copyError (oldError, parentKey);

	if (ns == KEY_NS_META)
	{
		clearError (parentKey);
		keyDel (oldError);
		ELEKTRA_SET_ERRORF (104, parentKey, "metakey with name \"%s\" passed to kdbGet", keyName (parentKey));
		return -1;
	}

	if (ns == KEY_NS_EMPTY)
	{
		ELEKTRA_ADD_WARNING (105, parentKey, "invalid key name passed to kdbGet");
	}

	int errnosave = errno;
	Key * initialParent = keyDup (parentKey);

	ELEKTRA_LOG ("now in new kdbGet (%s)", keyName (parentKey));

	Split * split = splitNew ();

	if (!handle || !ks)
	{
		clearError (parentKey);
		ELEKTRA_SET_ERROR (37, parentKey, "handle or ks null pointer");
		goto error;
	}

	elektraGlobalGet (handle, ks, parentKey, PREGETSTORAGE, INIT);
	elektraGlobalGet (handle, ks, parentKey, PREGETSTORAGE, MAXONCE);
	elektraGlobalGet (handle, ks, parentKey, PREGETSTORAGE, DEINIT);

	if (splitBuildup (split, handle, parentKey) == -1)
	{
		clearError (parentKey);
		ELEKTRA_SET_ERROR (38, parentKey, "error in splitBuildup");
		goto error;
	}

	// Check if a update is needed at all
	switch (elektraGetCheckUpdateNeeded (split, parentKey))
	{
	case 0: // We don't need an update so let's do nothing
		keySetName (parentKey, keyName (initialParent));
		elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, INIT);
		elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, MAXONCE);
		elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, DEINIT);
		splitUpdateFileName (split, handle, parentKey);
		keyDel (initialParent);
		splitDel (split);
		errno = errnosave;
		keyDel (oldError);
		return 0;
	case -1:
		goto error;
		// otherwise fall trough
	}

	// Appoint keys (some in the bypass)
	if (splitAppoint (split, handle, ks) == -1)
	{
		clearError (parentKey);
		ELEKTRA_SET_ERROR (38, parentKey, "error in splitAppoint");
		goto error;
	}

	if (handle->globalPlugins[POSTGETSTORAGE][FOREACH] || handle->globalPlugins[POSTGETCLEANUP][FOREACH])
	{
		clearError (parentKey);
		if (elektraGetDoUpdateWithGlobalHooks (NULL, split, NULL, parentKey, initialParent, FIRST) == -1)
		{
			goto error;
		}
		else
		{
			copyError (parentKey, oldError);
		}

		keySetName (parentKey, keyName (initialParent));

		if (splitGet (split, parentKey, handle) == -1)
		{
			ELEKTRA_ADD_WARNING (108, parentKey, keyName (ksCurrent (ks)));
			// continue, because sizes are already updated
		}
		ksClear (ks);
		splitMerge (split, ks);

		clearError (parentKey);
		if (elektraGetDoUpdateWithGlobalHooks (handle, split, ks, parentKey, initialParent, LAST) == -1)
		{
			goto error;
		}
		else
		{
			copyError (parentKey, oldError);
		}
	}
	else
	{

		/* Now do the real updating,
		   but not for bypassed keys in split->size-1 */
		clearError (parentKey);
		if (elektraGetDoUpdate (split, parentKey) == -1)
		{
			goto error;
		}
		else
		{
			copyError (parentKey, oldError);
		}
		/* Now post-process the updated keysets */
		if (splitGet (split, parentKey, handle) == -1)
		{
			ELEKTRA_ADD_WARNING (108, parentKey, keyName (ksCurrent (ks)));
			// continue, because sizes are already updated
		}
		/* We are finished, now just merge everything to returned */
		ksClear (ks);

		splitMerge (split, ks);
	}

	elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, INIT);
	elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, MAXONCE);
	elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, DEINIT);

	ksRewind (ks);

	keySetName (parentKey, keyName (initialParent));

	splitUpdateFileName (split, handle, parentKey);
	keyDel (initialParent);
	keyDel (oldError);
	splitDel (split);
	errno = errnosave;
	return 1;

error:
	keySetName (parentKey, keyName (initialParent));
	elektraGlobalError (handle, ks, parentKey, POSTGETSTORAGE, INIT);
	elektraGlobalError (handle, ks, parentKey, POSTGETSTORAGE, MAXONCE);
	elektraGlobalError (handle, ks, parentKey, POSTGETSTORAGE, DEINIT);

	keySetName (parentKey, keyName (initialParent));
	if (handle) splitUpdateFileName (split, handle, parentKey);
	keyDel (initialParent);
	keyDel (oldError);
	splitDel (split);
	errno = errnosave;
	return -1;
}
示例#4
0
文件: kdb.c 项目: KurtMi/libelektra
/**
 * @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;
}
示例#5
0
文件: kdb.c 项目: KurtMi/libelektra
/** @brief Set keys in an atomic and universal way.
 *
 * @pre kdbGet() must be called before kdbSet():
 *    - initially (after kdbOpen())
 *    - after conflict errors in kdbSet().
 *
 * @pre The @p returned KeySet must be a valid KeySet, e.g. constructed
 *     with ksNew().
 *
 * @pre The @p parentKey Key must be a valid Key, e.g. constructed with
 *     keyNew().
 *
 * If you pass NULL on any parameter kdbSet() will fail immediately without doing anything.
 *
 * With @p parentKey you can give an hint which part of the given keyset
 * is of interest for you. Then you promise to only modify or
 * remove keys below this key. All others would be passed back
 * as they were retrieved by kdbGet().
 *
 * @par Errors
 * If some error occurs:
 * - kdbSet() will leave the KeySet's * internal cursor on the key that generated the error.
 * - Error information will be written into the metadata of
 *   the parent key.
 * - None of the keys are actually committed in this situation, i.e. no
 *   configuration file will be modified.
 *
 * In case of errors you should present the error message to the user and let the user decide what
 * to do. Possible solutions are:
 * - remove the problematic key and use kdbSet() again (for validation or type errors)
 * - change the value of the problematic key and use kdbSet() again (for validation errors)
 * - do a kdbGet() (for conflicts, i.e. error 30) and then
 *   - set the same keyset again (in favour of what was set by this user)
 *   - drop the old keyset (in favour of what was set from another application)
 *   - merge the original, your own and the other keyset
 * - export the configuration into a file (for unresolvable errors)
 * - repeat the same kdbSet might be of limited use if the user does
 *   not explicitly request it, because temporary
 *   errors are rare and its unlikely that they fix themselves
 *   (e.g. disc full, permission problems)
 *
 * @par Optimization
 * Each key is checked with keyNeedSync() before being actually committed.
 * If no key of a backend needs to be synced
 * any affairs to backends are omitted and 0 is returned.
 *
 * @snippet kdbset.c set
 *
 * showElektraErrorDialog() and doElektraMerge() need to be implemented
 * by the user of Elektra. For doElektraMerge a 3-way merge algorithm exists in
 * libelektra-tools.
 *
 * @param handle contains internal information of @link kdbOpen() opened @endlink key database
 * @param ks a KeySet which should contain changed keys, otherwise nothing is done
 * @param parentKey is used to add warnings and set an error
 *         information. Additionally, its name is an hint which keys
 *         should be committed (it is possible that more are changed).
 *           - cascading keys (starting with /) will set the path in all namespaces
 *           - / will commit all keys
 *           - metanames will be rejected (error 104)
 *           - empty/invalid (error 105)
 * @retval 1 on success
 * @retval 0 if nothing had to be done, no changes in KDB
 * @retval -1 on failure, no changes in KDB
 * @see keyNeedSync()
 * @see ksCurrent() contains the error key
 * @see kdbOpen() and kdbGet() that must be called first
 * @see kdbClose() that must be called afterwards
 * @ingroup kdb
 */
int kdbSet (KDB * handle, KeySet * ks, Key * parentKey)
{
	elektraNamespace ns = keyGetNamespace (parentKey);
	if (ns == KEY_NS_NONE)
	{
		return -1;
	}
	Key * oldError = keyNew (keyName (parentKey), KEY_END);
	copyError (oldError, parentKey);

	if (ns == KEY_NS_META)
	{
		clearError (parentKey); // clear previous error to set new one
		ELEKTRA_SET_ERRORF (104, parentKey, "metakey with name \"%s\" passed to kdbSet", keyName (parentKey));
		keyDel (oldError);
		return -1;
	}

	if (ns == KEY_NS_EMPTY)
	{
		ELEKTRA_ADD_WARNING (105, parentKey, "invalid key name passed to kdbSet");
	}

	if (!handle || !ks)
	{
		clearError (parentKey); // clear previous error to set new one
		ELEKTRA_SET_ERROR (37, parentKey, "handle or ks null pointer");
		keyDel (oldError);
		return -1;
	}

	int errnosave = errno;
	Key * initialParent = keyDup (parentKey);

	ELEKTRA_LOG ("now in new kdbSet (%s) %p %zd", keyName (parentKey), (void *)handle, ksGetSize (ks));

	elektraGlobalSet (handle, ks, parentKey, PRESETSTORAGE, INIT);
	elektraGlobalSet (handle, ks, parentKey, PRESETSTORAGE, MAXONCE);
	elektraGlobalSet (handle, ks, parentKey, PRESETSTORAGE, DEINIT);

	ELEKTRA_LOG ("after presetstorage maxonce(%s) %p %zd", keyName (parentKey), (void *)handle, ksGetSize (ks));

	Split * split = splitNew ();
	Key * errorKey = 0;

	if (splitBuildup (split, handle, parentKey) == -1)
	{
		clearError (parentKey); // clear previous error to set new one
		ELEKTRA_SET_ERROR (38, parentKey, "error in splitBuildup");
		goto error;
	}

	// 1.) Search for syncbits
	int syncstate = splitDivide (split, handle, ks);
	if (syncstate == -1)
	{
		clearError (parentKey); // clear previous error to set new one
		ELEKTRA_SET_ERROR (8, parentKey, keyName (ksCurrent (ks)));
		goto error;
	}
	ELEKTRA_ASSERT (syncstate == 0 || syncstate == 1, "syncstate not 0 or 1, but %d", syncstate);

	// 2.) Search for changed sizes
	syncstate |= splitSync (split);
	ELEKTRA_ASSERT (syncstate <= 1, "syncstate not equal or below 1, but %d", syncstate);
	if (syncstate != 1)
	{
		/* No update is needed */
		keySetName (parentKey, keyName (initialParent));
		if (syncstate < 0) clearError (parentKey); // clear previous error to set new one
		if (syncstate == -1)
		{
			ELEKTRA_SET_ERROR (107, parentKey, "Assert failed: invalid namespace");
		}
		else if (syncstate < -1)
		{
			ELEKTRA_SET_ERROR (107, parentKey, keyName (split->parents[-syncstate - 2]));
		}
		keyDel (initialParent);
		splitDel (split);
		errno = errnosave;
		keyDel (oldError);
		return syncstate == 0 ? 0 : -1;
	}
	ELEKTRA_ASSERT (syncstate == 1, "syncstate not 1, but %d", syncstate);

	splitPrepare (split);

	clearError (parentKey); // clear previous error to set new one
	if (elektraSetPrepare (split, parentKey, &errorKey, handle->globalPlugins) == -1)
	{
		goto error;
	}
	else
	{
		// no error, restore old error
		copyError (parentKey, oldError);
	}
	keySetName (parentKey, keyName (initialParent));

	elektraGlobalSet (handle, ks, parentKey, PRECOMMIT, INIT);
	elektraGlobalSet (handle, ks, parentKey, PRECOMMIT, MAXONCE);
	elektraGlobalSet (handle, ks, parentKey, PRECOMMIT, DEINIT);

	elektraSetCommit (split, parentKey);

	elektraGlobalSet (handle, ks, parentKey, COMMIT, INIT);
	elektraGlobalSet (handle, ks, parentKey, COMMIT, MAXONCE);
	elektraGlobalSet (handle, ks, parentKey, COMMIT, DEINIT);

	splitUpdateSize (split);

	keySetName (parentKey, keyName (initialParent));

	elektraGlobalSet (handle, ks, parentKey, POSTCOMMIT, INIT);
	elektraGlobalSet (handle, ks, parentKey, POSTCOMMIT, MAXONCE);
	elektraGlobalSet (handle, ks, parentKey, POSTCOMMIT, DEINIT);

	for (size_t i = 0; i < ks->size; ++i)
	{
		// remove all flags from all keys
		clear_bit (ks->array[i]->flags, KEY_FLAG_SYNC);
	}

	keySetName (parentKey, keyName (initialParent));
	keyDel (initialParent);
	splitDel (split);

	keyDel (oldError);
	errno = errnosave;
	return 1;

error:
	keySetName (parentKey, keyName (initialParent));

	elektraGlobalError (handle, ks, parentKey, PREROLLBACK, INIT);
	elektraGlobalError (handle, ks, parentKey, PREROLLBACK, MAXONCE);
	elektraGlobalError (handle, ks, parentKey, PREROLLBACK, DEINIT);

	elektraSetRollback (split, parentKey);

	if (errorKey)
	{
		Key * found = ksLookup (ks, errorKey, 0);
		if (!found)
		{
			ELEKTRA_ADD_WARNING (82, parentKey, keyName (errorKey));
		}
	}

	keySetName (parentKey, keyName (initialParent));

	elektraGlobalError (handle, ks, parentKey, POSTROLLBACK, INIT);
	elektraGlobalError (handle, ks, parentKey, POSTROLLBACK, MAXONCE);
	elektraGlobalError (handle, ks, parentKey, POSTROLLBACK, DEINIT);

	keySetName (parentKey, keyName (initialParent));
	keyDel (initialParent);
	splitDel (split);
	errno = errnosave;
	keyDel (oldError);
	return -1;
}