Ejemplo n.º 1
0
//! [Basic Copy All]
void l(Key *k)
{
	// receive c
	keyCopyAllMeta(k, c);
	// the caller will see the changed key k
	// with all the metadata from c
}
Ejemplo n.º 2
0
int elektraGlobMatch (Key * key, const Key * match, const char * globFlags)
{
	char * tokenList = elektraStrDup (globFlags);
	char delimiter[] = ",";
	char * flagName = strtok (tokenList, delimiter);

	int flags = 0;
	while (flagName != NULL)
	{
		for (size_t i = 0; i < sizeof (flagMaps) / sizeof (struct GlobFlagMap); i++)
		{
			if (!strcmp (flagName, flagMaps[i].name))
			{
				flags |= flagMaps[i].flag;
			}
		}
		flagName = strtok (NULL, delimiter);
	}

	free (tokenList);

	if (!fnmatch (keyString (match), keyName (key), flags))
	{
		keyCopyAllMeta (key, match);
		return 1;
	}

	return 0;
}
Ejemplo n.º 3
0
//! [Shared Meta All]
void o(KeySet *ks)
{
	Key *current;
	Key *shared = keyNew (0);
	keySetMeta(shared, "shared1", "this meta data should be shared among many keys");
	keySetMeta(shared, "shared2", "this meta data should be shared among many keys also");
	keySetMeta(shared, "shared3", "this meta data should be shared among many keys too");

	ksRewind(ks);
	while ((current = ksNext(ks)) != 0)
	{
		if (needsSharedData(current)) keyCopyAllMeta(current, shared);
	}

	keyDel(shared);
}
Ejemplo 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
}
Ejemplo n.º 5
0
void test_copyall()
{
	printf ("Test key meta copy all\n");

	Key *key1;
	Key *key2;

	succeed_if (key1 = keyNew(0), "could not create key");
	succeed_if (key2 = keyNew(0), "could not create key");

	succeed_if (keyCopyAllMeta(key2, key1) == 0, "could not do anything");

	succeed_if (keyValue(keyGetMeta(key2, "nonexist")) == 0, "should not be there");

	keyDel (key1);
	keyDel (key2);


	succeed_if (key1 = keyNew(0), "could not create key");
	succeed_if (key2 = keyNew(0), "could not create key");

	succeed_if (keySetMeta(key1, "mymeta", "a longer meta value") == sizeof("a longer meta value"),
			"could not set meta value");
	succeed_if (keyCopyAllMeta(key2, key1) == 1, "could not copy meta value");
	succeed_if (!strcmp(keyValue(keyGetMeta(key1, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (!strcmp(keyValue(keyGetMeta(key2, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (keyGetMeta(key1, "mymeta") == keyGetMeta(key2, "mymeta"), "reference to the same key");

	succeed_if (keyCopyAllMeta(key1, key2) == 1, "did nothing in the end");
	succeed_if (!strcmp(keyValue(keyGetMeta(key1, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (!strcmp(keyValue(keyGetMeta(key2, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (keyGetMeta(key1, "mymeta") == keyGetMeta(key2, "mymeta"), "reference to the same key");

	keyDel (key1);
	keyDel (key2);


	succeed_if (key1 = keyNew(0), "could not create key");
	succeed_if (key2 = keyNew(0), "could not create key");

	succeed_if (keySetMeta(key1, "mymeta", "a longer meta value") == sizeof("a longer meta value"),
			"could not set meta value");
	succeed_if (keyCopyAllMeta(key2, key1) == 1, "could not copy meta value");
	succeed_if (!strcmp(keyValue(keyGetMeta(key1, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (!strcmp(keyValue(keyGetMeta(key2, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (keyGetMeta(key1, "mymeta") == keyGetMeta(key2, "mymeta"), "reference to the same key");

	succeed_if (keySetMeta(key1, "mymeta", "a longer meta value") == sizeof("a longer meta value"),
			"could not set meta value");
	succeed_if (!strcmp(keyValue(keyGetMeta(key1, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (!strcmp(keyValue(keyGetMeta(key2, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (keyGetMeta(key1, "mymeta") != keyGetMeta(key2, "mymeta"), "reference to another key");

	succeed_if (keySetMeta(key1, "mymeta", "a longer meta value2") == sizeof("a longer meta value2"),
			"could not set meta value2");
	succeed_if (!strcmp(keyValue(keyGetMeta(key1, "mymeta")), "a longer meta value2"), "old meta data should be unchanged");
	succeed_if (!strcmp(keyValue(keyGetMeta(key2, "mymeta")), "a longer meta value"), "old meta data should be unchanged");
	succeed_if (keyGetMeta(key1, "mymeta") != keyGetMeta(key2, "mymeta"),
			"reference to another key (with another value)");

	keyDel (key1);
	keyDel (key2);

	Key *k;
	Key *c;

	k=keyNew ("user/metakey",
		KEY_META, "t", "test1",
		KEY_META, "a", "another",
		KEY_META, "cya", "see the meta data later",
		KEY_META, "mode", "0775",
		KEY_END);
	c=keyNew ("user/metacopy", KEY_END);

	succeed_if (keyGetMeta(k, "t") != 0, "could not get meta key");
	succeed_if (keyGetMeta(k, "a") != 0, "could not get meta key");

	succeed_if (keyGetMeta(c, "t") == 0, "could get meta key not there");
	succeed_if (keyGetMeta(c, "a") == 0, "could get meta key not there");

	succeed_if (keyCopyAllMeta(c, k) == 1, "could not copy meta data");
	succeed_if (keyGetMeta(k, "t") == keyGetMeta(c, "t"), "not the same meta data after copy");
	succeed_if (keyGetMeta(k, "a") == keyGetMeta(c, "a"), "not the same meta data after copy");
	succeed_if (keyGetMeta(k, "cya") == keyGetMeta(c, "cya"), "not the same meta data after copy");
	succeed_if (keyGetMeta(k, "mode") == keyGetMeta(c, "mode"), "not the same meta data after copy");
	succeed_if (keyValue(keyGetMeta(k, "nonexist")) == 0, "should not be there");
	succeed_if (keyValue(keyGetMeta(c, "nonexist")) == 0, "should not be there");

	succeed_if (keyCopyAllMeta(c, k) == 1, "could not copy meta data (again)");
	succeed_if (keyGetMeta(k, "t") == keyGetMeta(c, "t"), "not the same meta data after copy");
	succeed_if (keyGetMeta(k, "a") == keyGetMeta(c, "a"), "not the same meta data after copy");
	succeed_if (keyGetMeta(k, "cya") == keyGetMeta(c, "cya"), "not the same meta data after copy");
	succeed_if (keyGetMeta(k, "mode") == keyGetMeta(c, "mode"), "not the same meta data after copy");
	succeed_if (keyValue(keyGetMeta(k, "nonexist")) == 0, "should not be there");
	succeed_if (keyValue(keyGetMeta(c, "nonexist")) == 0, "should not be there");

	keyDel (k);
	keyDel (c);
}