Exemplo n.º 1
0
static void test_mmap_ksCopy (const char * tmpFile)
{
	Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("mmapstorage");

	KeySet * ks = simpleTestKeySet ();
	succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
	succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
	succeed_if ((ks->flags & KS_FLAG_MMAP_ARRAY) == KS_FLAG_MMAP_ARRAY, "KeySet array not in mmap");

	KeySet * copyKs = ksNew (0, KS_END);
	if (ksCopy (copyKs, ks) == 1)
	{
		compare_keyset (copyKs, ks);
		compare_keyset (ks, copyKs);
	}
	else
	{
		yield_error ("ksCopy failed");
	}

	ksDel (copyKs);
	keyDel (parentKey);
	ksDel (ks);
	PLUGIN_CLOSE ();
}
Exemplo n.º 2
0
static void test_ksCopy (const size_t storagePlugin, const char * tmpFile)
{
	Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
	open_storage_plugin (storagePlugin);
	Plugin * plugin = plugins[storagePlugin];

	KeySet * ks = simpleTestKeySet ();
	succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
	succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");

	KeySet * copyKs = ksNew (0, KS_END);
	if (ksCopy (copyKs, ks) == 1)
	{
		compare_keyset (copyKs, ks);
		compare_keyset (ks, copyKs);
	}
	else
	{
		yield_error ("ksCopy failed");
	}

	ksDel (copyKs);
	keyDel (parentKey);
	ksDel (ks);
	closeStoragePlugin (storagePlugin);
}
Exemplo n.º 3
0
static void test_mmap_ks_copy_with_meta (const char * tmpFile)
{
	Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("mmapstorage");
	KeySet * ks = metaTestKeySet ();
	succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
	ksDel (ks);

	KeySet * returned = ksNew (0, KS_END);

	succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");

	KeySet * expected = metaTestKeySet ();
	compare_keyset (expected, returned);

	KeySet * copiedKs = ksNew (0, KS_END);
	ksCopy (copiedKs, returned);
	compare_keyset (expected, copiedKs);

	ksDel (copiedKs);
	ksDel (expected);
	ksDel (returned);

	keyDel (parentKey);
	PLUGIN_CLOSE ();
}
Exemplo n.º 4
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.º 5
0
static void test_ksResize ()
{
    int i;
    KeySet * ks = 0;
    KeySet * copy = ksNew (0, KS_END);
    char name[NAME_SIZE];

    ks = ksNew (20, keyNew ("user/test01", KEY_END), keyNew ("user/test02", KEY_END), keyNew ("user/test03", KEY_END),
                keyNew ("user/test04", KEY_END), keyNew ("user/test05", KEY_END), keyNew ("user/test11", KEY_END),
                keyNew ("user/test12", KEY_END), keyNew ("user/test13", KEY_END), keyNew ("user/test14", KEY_END),
                keyNew ("user/test15", KEY_END), keyNew ("user/test21", KEY_END), keyNew ("user/test22", KEY_END),
                keyNew ("user/test23", KEY_END), keyNew ("user/test24", KEY_END), keyNew ("user/test25", KEY_END),
                keyNew ("user/test31", KEY_END), keyNew ("user/test32", KEY_END), keyNew ("user/test33", KEY_END),
                keyNew ("user/test34", KEY_END), keyNew ("user/test35", KEY_END), KS_END);
    succeed_if (ksGetAlloc (ks) == 20, "20 keys with alloc 20 should work");
    ksDel (ks);

    printf ("Test resize of keyset\n");
    exit_if_fail ((ks = ksNew (0, KS_END)) != 0, "could not create new keyset");
    for (i = 0; i < 100; i++)
    {
        snprintf (name, NAME_SIZE, "user/test%d", i);
        ksAppendKey (ks, keyNew (name, KEY_END));
        if (i >= 63)
        {
            succeed_if (ksGetAlloc (ks) == 127, "allocation size wrong");
        }
        else if (i >= 31)
        {
            succeed_if (ksGetAlloc (ks) == 63, "allocation size wrong");
        }
        else if (i >= 15)
        {
            succeed_if (ksGetAlloc (ks) == 31, "allocation size wrong");
        }
        else if (i >= 0)
        {
            succeed_if (ksGetAlloc (ks) == 15, "allocation size wrong");
        }
    }
    succeed_if (ksGetSize (ks) == 100, "could not append 100 keys");
    succeed_if (ksGetAlloc (ks) == 127, "allocation size wrong");
    for (i = 100; i >= 0; i--)
    {
        keyDel (ksPop (ks));
        if (i >= 64)
        {
            succeed_if (ksGetAlloc (ks) == 127, "allocation size wrong");
        }
        else if (i >= 32)
        {
            succeed_if (ksGetAlloc (ks) == 63, "allocation size wrong");
        }
        else if (i >= 16)
        {
            succeed_if (ksGetAlloc (ks) == 31, "allocation size wrong");
        }
        else if (i >= 0)
        {
            succeed_if (ksGetAlloc (ks) == 15, "allocation size wrong");
        }
    }
    succeed_if (ksGetSize (ks) == 0, "could not pop 100 keys");
    succeed_if (ksGetAlloc (ks) == 15, "allocation size wrong");
    ksDel (ks);

    exit_if_fail ((ks = ksNew (0, KS_END)) != 0, "could not create new keyset");
    ksResize (ks, 100);
    succeed_if (ksGetAlloc (ks) == 100, "allocation size wrong");
    for (i = 0; i < 100; i++)
    {
        snprintf (name, NAME_SIZE, "user/test%d", i);
        ksAppendKey (ks, keyNew (name, KEY_END));
        succeed_if (ksGetAlloc (ks) == 100, "allocation size wrong");
    }
    succeed_if (ksGetSize (ks) == 100, "could not append 100 keys");
    succeed_if (ksGetAlloc (ks) == 100, "allocation size wrong");
    ksDel (ks);

    ks =
#include "data_keyset.c"

        succeed_if (ksGetSize (ks) == 102, "Problem loading keyset with 102 keys");
    succeed_if (ksGetAlloc (ks) == 102, "alloc size wrong");

    ksCopy (copy, ks);
    succeed_if (ksGetSize (copy) == 102, "Problem copy keyset with 102 keys");
    succeed_if (ksGetAlloc (copy) == 127, "alloc of copy size wrong");

    compare_keyset (copy, ks);

    ksClear (copy); // useless, just test for double free
    ksCopy (copy, ks);

    succeed_if (ksGetSize (copy) == 102, "Problem copy keyset with 102 keys");
    succeed_if (ksGetAlloc (copy) == 127, "alloc of copy size wrong");
    compare_keyset (copy, ks);

    ksDel (copy);
    ksDel (ks);
}