Ejemplo n.º 1
0
static void elektraResolveUser (resolverHandle * p, Key * warningsKey)
{
	p->filename = elektraMalloc (KDB_MAX_PATH_LENGTH);

#if defined(_WIN32)
	CHAR home[MAX_PATH];
	if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_PROFILE, NULL, 0, home)))
	{
		escapePath (home);
	}
	else
	{
		strcpy (home, "");
		ELEKTRA_ADD_WARNING (90, warningsKey, "could not get home (CSIDL_PROFILE), using /");
	}
#else
	char * home = (char *)getenv ("HOME");
	if (!home)
	{
		home = "";
		ELEKTRA_ADD_WARNING (90, warningsKey, "could not get home, using /");
	}
#endif

	strcpy (p->filename, home);
	strcat (p->filename, "/");
	strncat (p->filename, p->path, KDB_MAX_PATH_LENGTH);
}
Ejemplo n.º 2
0
static int elektraResolvePasswdHome (resolverHandle * p, Key * warningsKey)
{
	ssize_t bufSize = sysconf (_SC_GETPW_R_SIZE_MAX);
	if (bufSize == -1) bufSize = 16384; // man 3 getpwuid

	char * buf = elektraMalloc (bufSize);
	if (!buf) return -1;
	struct passwd pwd;
	struct passwd * result;
	int s;

	s = getpwuid_r (getuid (), &pwd, buf, bufSize, &result);
	if (result == NULL)
	{
		elektraFree (buf);
		if (s != 0)
		{
			ELEKTRA_ADD_WARNING (90, warningsKey, strerror (s));
		}
		return -1;
	}

	const char * home = pwd.pw_dir;
	size_t filenameSize = elektraStrLen (home) + elektraStrLen (p->path) - 1;

	p->filename = elektraMalloc (filenameSize);
	snprintf (p->filename, filenameSize, "%s/%s", home, (p->path) + 2);

	elektraFree (buf);
	return 0;
}
Ejemplo n.º 3
0
static void elektraDropCurrentKey (KeySet * ks, Key * warningKey, const Backend * curHandle, const char * msg)
{
	const Key * k = ksCurrent (ks);

	const size_t sizeOfStaticText = 100;
	char * warningMsg = elektraMalloc (keyGetNameSize (curHandle->mountpoint) + keyGetValueSize (curHandle->mountpoint) +
					   keyGetNameSize (k) + strlen (msg) + sizeOfStaticText);
	strcpy (warningMsg, "drop key ");
	const char * name = keyName (k);
	if (name)
	{
		strcat (warningMsg, name);
	}
	else
	{
		strcat (warningMsg, "(no name)");
	}
	strcat (warningMsg, " not belonging to ");
	strcat (warningMsg, keyName (curHandle->mountpoint));
	strcat (warningMsg, " with name ");
	strcat (warningMsg, keyString (curHandle->mountpoint));
	strcat (warningMsg, " because ");
	strcat (warningMsg, msg);
	ELEKTRA_ADD_WARNING (79, warningKey, warningMsg);
	elektraFree (warningMsg);
	cursor_t c = ksGetCursor (ks);
	keyDel (elektraKsPopAtCursor (ks, c));
	ksSetCursor (ks, c);
	elektraKsPrev (ks); // next ksNext() will point correctly again
}
Ejemplo n.º 4
0
static void elektraResolveSystem (resolverHandle * p, Key * errorKey)
{
	char * system = getenv ("ALLUSERSPROFILE");

	if (!system)
	{
		system = "";
		ELEKTRA_ADD_WARNING (90, errorKey, "could not get ALLUSERSPROFILE, using /");
	}
	else
	{
		escapePath (system);
	}

	if (p->path[0] == '/')
	{
		/* Use absolute path */
		size_t filenameSize = strlen (system) + strlen (p->path) + 1;
		p->filename = elektraMalloc (filenameSize);
		strcpy (p->filename, system);
		strcat (p->filename, p->path);
		return;
	}
	size_t filenameSize = sizeof (KDB_DB_SYSTEM) + strlen (system) + strlen (p->path) + sizeof ("/") + 1;
	p->filename = elektraMalloc (filenameSize);
	strcpy (p->filename, system);
	strcat (p->filename, KDB_DB_SYSTEM);
	strcat (p->filename, "/");
	strcat (p->filename, p->path);
	return;
}
Ejemplo n.º 5
0
/**
 * Closes the session with the Key database.
 *
 * @pre The handle must be a valid handle as returned from kdbOpen()
 *
 * @pre errorKey must be a valid key, e.g. created with keyNew()
 *
 * This is the counterpart of kdbOpen().
 *
 * You must call this method when you finished your affairs with the key
 * database. You can manipulate Key and KeySet objects also after
 * kdbClose(), but you must not use any kdb*() call afterwards.
 *
 * The @p handle parameter will be finalized and all resources associated to it
 * will be freed. After a kdbClose(), the @p handle cannot be used anymore.
 *
 * @param handle contains internal information of
 *               @link kdbOpen() opened @endlink key database
 * @param errorKey the key which holds error/warning information
 * @retval 0 on success
 * @retval -1 on NULL pointer
 * @ingroup kdb
 */
int kdbClose (KDB * handle, Key * errorKey)
{
	if (!handle)
	{
		return -1;
	}

	Key * initialParent = keyDup (errorKey);
	int errnosave = errno;
	splitDel (handle->split);

	trieClose (handle->trie, errorKey);

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

	// not set in fallback mode, so lets check:
	if (handle->initBackend)
	{
		backendClose (handle->initBackend, errorKey);
		handle->initBackend = 0;
	}

	for (int i = 0; i < NR_GLOBAL_POSITIONS; ++i)
	{
		for (int j = 0; j < NR_GLOBAL_SUBPOSITIONS; ++j)
		{
			elektraPluginClose (handle->globalPlugins[i][j], errorKey);
		}
	}

	if (handle->modules)
	{
		elektraModulesClose (handle->modules, errorKey);
		ksDel (handle->modules);
	}
	else
	{
		ELEKTRA_ADD_WARNING (47, errorKey, "modules were not open");
	}

	elektraFree (handle);

	keySetName (errorKey, keyName (initialParent));
	keySetString (errorKey, keyString (initialParent));
	keyDel (initialParent);
	errno = errnosave;
	return 0;
}
Ejemplo n.º 6
0
/**
 * @brief read the desired iteration count from config
 * @param errorKey may hold a warning if an invalid configuration is provided
 * @param config KeySet holding the plugin configuration
 * @returns the number of iterations for the key derivation function
 */
kdb_unsigned_long_t CRYPTO_PLUGIN_FUNCTION (getIterationCount) (Key * errorKey, KeySet * config)
{
	Key * k = ksLookupByName (config, ELEKTRA_CRYPTO_PARAM_ITERATION_COUNT, 0);
	if (k)
	{
		const kdb_unsigned_long_t iterations = strtoul (keyString (k), NULL, 10);
		if (iterations > 0)
		{
			return iterations;
		}
		else
		{
			ELEKTRA_ADD_WARNING (ELEKTRA_WARNING_CRYPTO_CONFIG, errorKey,
					     "iteration count provided at " ELEKTRA_CRYPTO_PARAM_ITERATION_COUNT
					     " is invalid. Using default value instead.");
		}
	}
	return ELEKTRA_CRYPTO_DEFAULT_ITERATION_COUNT;
}
Ejemplo n.º 7
0
static int elektraResolvePasswd (resolverHandle * p, Key * warningsKey)
{
	struct passwd pwd;
	struct passwd * result;
	char * buf;
	ssize_t bufsize;
	int s;

	bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
	if (bufsize == -1) /* Value was indeterminate */
	{
		bufsize = 16384; /* Should be more than enough */
	}

	buf = elektraMalloc (bufsize);
	if (buf == NULL)
	{
		return 0;
	}

	s = getpwuid_r (getuid (), &pwd, buf, bufsize, &result);
	if (result == NULL)
	{
		elektraFree (buf);
		if (s != 0)
		{
			ELEKTRA_ADD_WARNING (90, warningsKey, strerror (s));
		}
		return 0;
	}

	/*
	printf("Info: %s; UID: %ld0, Home: %s\n",
			pwd.pw_gecos,
			(long) pwd.pw_uid,
			pwd.pw_dir);
	*/

	elektraResolveUsingHome (p, pwd.pw_dir, true);
	elektraFree (buf);

	return 1;
}
Ejemplo n.º 8
0
int elektraPluginClose (Plugin * handle, Key * errorKey)
{
	int rc = 0;

	if (!handle) return 0;

	--handle->refcounter;

	/* Check if we have the last reference on the plugin (unsigned!) */
	if (handle->refcounter > 0) return 0;

	if (handle->kdbClose)
	{
		rc = handle->kdbClose (handle, errorKey);
		if (rc == -1) ELEKTRA_ADD_WARNING (12, errorKey, "kdbClose() failed");
	}

	ksDel (handle->config);
	elektraFree (handle);

	return rc;
}
Ejemplo n.º 9
0
/**
 * @return freshly allocated buffer with current working directory
 *
 * @param warningsKey where warnings are added
 */
static char * elektraGetCwd (Key * warningsKey)
{
	int size = 4096;
	char * cwd = elektraMalloc (size);
	if (cwd == NULL)
	{
		ELEKTRA_ADD_WARNING (83, warningsKey, "could not alloc for getcwd, defaulting to /");
		return 0;
	}

	char * ret = NULL;
	while (ret == NULL)
	{
		ret = getcwd (cwd, size);

		if (ret == NULL)
		{
			if (errno != ERANGE)
			{
				// give up, we cannot handle the problem
				elektraFree (cwd);
				ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey,
						      "getcwd failed with errno %d \"%s\", defaulting to /", errno, strerror (errno));
				return 0;
			}

			// try to double the space
			size *= 2;
			elektraRealloc ((void **) &cwd, size);
			if (cwd == NULL)
			{
				ELEKTRA_ADD_WARNINGF (83, warningsKey, "could not realloc for getcwd size %d, defaulting to /", size);
				return 0;
			}
		}
	}

	return ret;
}
Ejemplo n.º 10
0
	/**This function avoid that every return path need to release the
	  * configuration. */
	inline static int openHelper (ckdb::Plugin * handle, kdb::KeySet & config, ckdb::Key * errorKey, Builder builder)
	{
		if (config.lookup ("/module"))
		{
			// suppress warnings if it is just a module
			// don't buildup the Delegated then
			return 0;
		}

		try
		{
			elektraPluginSetData (handle, (*builder) (config));
		}
		catch (const char * msg)
		{
#ifdef KDBERRORS_H
			ELEKTRA_ADD_WARNING (69, errorKey, msg);
#endif
			return -1;
		}

		return get (handle) != nullptr ? 1 : -1;
	}
Ejemplo n.º 11
0
/**
 * @internal
 * @brief Does the rollback
 *
 * @param split all information for iteration
 * @param parentKey to add warnings (also passed to plugins for the same reason)
 */
static void elektraSetRollback (Split * split, Key * parentKey)
{
	for (size_t p = 0; p < NR_OF_PLUGINS; ++p)
	{
		for (size_t i = 0; i < split->size; i++)
		{
			int ret = 0;
			Backend * backend = split->handles[i];

			ksRewind (split->keysets[i]);
			if (backend->errorplugins[p])
			{
				keySetName (parentKey, keyName (split->parents[i]));
				ret = backend->errorplugins[p]->kdbError (backend->errorplugins[p], split->keysets[i], parentKey);
			}

			if (ret == -1)
			{
				ELEKTRA_ADD_WARNING (81, parentKey, keyName (backend->mountpoint));
			}
		}
	}
}
Ejemplo n.º 12
0
/**
 * @internal
 * @brief Does the commit
 *
 * @param split all information for iteration
 * @param parentKey to add warnings (also passed to plugins for the same reason)
 */
static void elektraSetCommit (Split * split, Key * parentKey)
{
	for (size_t p = COMMIT_PLUGIN; p < NR_OF_PLUGINS; ++p)
	{
		for (size_t i = 0; i < split->size; i++)
		{
			int ret = 0;
			Backend * backend = split->handles[i];

			if (backend->setplugins[p] && backend->setplugins[p]->kdbSet)
			{
				if (p != COMMIT_PLUGIN)
				{
					keySetString (parentKey, keyString (split->parents[i]));
				}
				keySetName (parentKey, keyName (split->parents[i]));
#if DEBUG && VERBOSE
				printf ("elektraSetCommit: %p # %zu with %s - %s\n", backend, p, keyName (parentKey),
					keyString (parentKey));
#endif
				ksRewind (split->keysets[i]);
				ret = backend->setplugins[p]->kdbSet (backend->setplugins[p], split->keysets[i], parentKey);
				if (p == COMMIT_PLUGIN)
				{
					// name of non-temp file
					keySetString (split->parents[i], keyString (parentKey));
				}
			}

			if (ret == -1)
			{
				ELEKTRA_ADD_WARNING (80, parentKey, keyName (backend->mountpoint));
			}
		}
	}
}
Ejemplo n.º 13
0
static char * elektraResolvePasswd (Key * warningsKey)
{
	ssize_t bufSize = sysconf (_SC_GETPW_R_SIZE_MAX);
	if (bufSize == -1) bufSize = 16384; // man 3 getpwuid

	char * buf = elektraMalloc (bufSize);
	if (!buf) return NULL;
	struct passwd pwd;
	struct passwd * result;

	int s = getpwuid_r (getuid (), &pwd, buf, bufSize, &result);
	if (result == NULL)
	{
		elektraFree (buf);
		if (s != 0)
		{
			ELEKTRA_ADD_WARNING (90, warningsKey, strerror (s));
		}
		return NULL;
	}
	char * resolved = elektraStrDup (pwd.pw_dir);
	elektraFree (buf);
	return resolved;
}
Ejemplo n.º 14
0
/**Builds a backend out of the configuration supplied
 * from:
 *
@verbatim
system/elektra/mountpoints/<name>
@endverbatim
 *
 * The root key must be like the above example. You do
 * not need to rewind the keyset. But every key must be
 * below the root key.
 *
 * The internal consistency will be checked in this
 * function. If necessary parts are missing, like
 * no plugins, they cant be loaded or similar 0
 * will be returned.
 *
 * ksCut() is perfectly suitable for cutting out the
 * configuration like needed.
 *
 * @note The given KeySet will be deleted within the function,
 * don't use it afterwards.
 *
 * @param elektraConfig the configuration to work with.
 *        It is used to build up this backend.
 * @param modules used to load new modules or get references
 *        to existing one
 * @return a pointer to a freshly allocated backend
 *         this could be the requested backend or a so called
 *         "missing backend".
 * @retval 0 if out of memory
 * @ingroup backend
 */
Backend* elektraBackendOpen(KeySet *elektraConfig, KeySet *modules, Key *errorKey)
{
	Key * cur;
	Key * root;
	KeySet *referencePlugins = 0;
	KeySet *systemConfig = 0;
	int failure = 0;

	referencePlugins = ksNew(0, KS_END);
	ksRewind(elektraConfig);

	root = ksNext (elektraConfig);

	Backend *backend = elektraBackendAllocate();

	while ((cur = ksNext(elektraConfig)) != 0)
	{
		if (keyRel (root, cur) == 1)
		{
			// direct below root key
			KeySet *cut = ksCut (elektraConfig, cur);
			if (!strcmp(keyBaseName(cur), "config"))
			{
				systemConfig = elektraRenameKeys(cut, "system");
				ksDel (cut);
			}
			else if (!strcmp(keyBaseName(cur), "getplugins"))
			{
				if (elektraProcessPlugins(backend->getplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(13, errorKey, "elektraProcessPlugins for get failed");
					failure = 1;
				}
			}
			else if (!strcmp(keyBaseName(cur), "mountpoint"))
			{
				backend->mountpoint = keyNew("",
						KEY_VALUE, keyBaseName(root), KEY_END);
				elektraKeySetName(backend->mountpoint, keyString(cur),
						KEY_CASCADING_NAME | KEY_EMPTY_NAME);

				if (!backend->mountpoint)
				{
					if (!failure) ELEKTRA_ADD_WARNINGF(14, errorKey,
						"Could not create mountpoint with name %s and value %s",
						keyString(cur), keyBaseName(root));
					failure = 1;
				}

				keyIncRef(backend->mountpoint);
				ksDel (cut);
			}
			else if (!strcmp(keyBaseName(cur), "setplugins"))
			{
				if (elektraProcessPlugins(backend->setplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for set failed");
					failure = 1;
				}
			}
			else if (!strcmp(keyBaseName(cur), "errorplugins"))
			{
				if (elektraProcessPlugins(backend->errorplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for error failed");
					failure = 1;
				}
			} else {
				// no one cares about that config
				if (!failure) ELEKTRA_ADD_WARNING(16, errorKey, keyBaseName(cur));
				ksDel (cut);
			}
		}
	}

	if (failure)
	{
		Backend *tmpBackend = elektraBackendOpenMissing(backend->mountpoint);
		elektraBackendClose(backend, errorKey);
		backend = tmpBackend;
	}

	ksDel (systemConfig);
	ksDel (elektraConfig);
	ksDel (referencePlugins);

	return backend;
}
Ejemplo n.º 15
0
/** @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;
}
Ejemplo n.º 16
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;
}
Ejemplo n.º 17
0
/**
 * @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;
}
Ejemplo n.º 18
0
static int csvRead(KeySet *returned, Key *parentKey, char delim, short useHeader, unsigned long fixColumnCount, const char **colNames)
{
    const char *fileName;
    fileName = keyString(parentKey);
    FILE *fp = NULL;
    fp = fopen(fileName, "rb");
    if(!fp)
    {
        ELEKTRA_SET_ERRORF(116, parentKey, "couldn't open file %s\n", fileName);
        return -1;
    }

    unsigned long length = 0;
    length = getLineLength(fp);
    if(length == 0)
    {
        ELEKTRA_ADD_WARNING(118, parentKey, "Empty file");
        fclose(fp);
        return -2;
    }

    char *lineBuffer;
    lineBuffer = elektraMalloc((length * sizeof(char))+1);
    if(!lineBuffer)
    {
        ELEKTRA_SET_ERROR(87, parentKey, "Out of memory");
        return -1;
    }
    if(!fgets(lineBuffer, length, fp))
    {
        ELEKTRA_SET_ERROR(116, parentKey, "Cant read from file");
        return -1;
    }

    unsigned long columns = 0;
    columns = getColumnCount(lineBuffer, delim);
    if(fixColumnCount)
    {
        if(columns != fixColumnCount)
        {
            ELEKTRA_SET_ERROR(117, parentKey, "illegal number of columns in Header line");
            elektraFree(lineBuffer);
            fclose(fp);
            return -1;
        }
    }
    unsigned long colCounter = 0;
    unsigned long lineCounter = 0;
    unsigned long offset = 0;
    char *col;
    char buf[INTSTR_MAX];
    int nr_keys = 1;
    KeySet *header = ksNew(0, KS_END);
    Key *key;

    if(useHeader == 1)
    {
        colCounter = 0;
        offset = 0;
        while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL)
        {
            offset += elektraStrLen(col);
            key = keyDup(parentKey);
            if(colNames && (colNames+colCounter))
            {
                keyAddBaseName(key, colNames[colCounter]);
            }
            else
            {
                keyAddBaseName(key, col);
            }
            keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1));
            ksAppendKey(header, key);
            ++colCounter;
        }
        fseek(fp, 0, SEEK_SET);
    }
    else
    {
        colCounter = 0;
        //if no headerline exists name the columns 0..N where N is the number of columns
        key = keyDup(parentKey);
        keyAddName(key, "#");
        while(colCounter < columns)
        {
            if(elektraArrayIncName(key) == -1)
            {
                elektraFree(lineBuffer);
                keyDel(key);
                ksDel(header);
                fclose(fp);
                return -1;
            }
            keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1));
            if(colNames && (colNames+colCounter))
                keySetBaseName(key, colNames[colCounter]);
            ksAppendKey(header, keyDup(key));
            ++colCounter;
        }
        keyDel(key);
        if(useHeader == 0)
            fseek(fp, 0, SEEK_SET);
    }
    Key *dirKey;
    Key *cur;
    dirKey = keyDup(parentKey);
    keyAddName(dirKey, "#");
    while(!feof(fp))
    {
        length = getLineLength(fp);
        if(length == 0)
            break;
        if(elektraRealloc((void **)&lineBuffer, (length * sizeof(char))+1) < 0)
        {
            fclose(fp);
            elektraFree(lineBuffer);
            ksDel(header);
            keyDel(dirKey);
            ELEKTRA_SET_ERROR(87, parentKey, "Out of memory");
            return -1;
        }
        fgets(lineBuffer, length, fp);
        if(elektraArrayIncName(dirKey) == -1)
        {
            elektraFree(lineBuffer);
            keyDel(dirKey);
            ksDel(header);
            fclose(fp);
            return -1;
        }
        ++nr_keys;
        offset = 0;
        colCounter = 0;
        char *lastIndex = "#0";
        while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL)
        {
            cur = getKeyByOrderNr(header, colCounter);
            offset += elektraStrLen(col);
            key = keyDup(dirKey);
            keyAddBaseName(key, keyBaseName(cur));
            keySetString(key, col);
            keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1));
            ksAppendKey(returned, key);
            lastIndex = (char *)keyBaseName(key);
            ++nr_keys;
            ++colCounter;
        }
        keySetString(dirKey, lastIndex);
        ksAppendKey(returned, keyDup(dirKey));
        if(colCounter != columns)
        {
            if(fixColumnCount)
            {
                ELEKTRA_SET_ERRORF(117, parentKey, "illegal number of columns in line %lu", lineCounter);
                elektraFree(lineBuffer);
                fclose(fp);
                keyDel(dirKey);
                ksDel(header);
                return -1;
            }
            ELEKTRA_ADD_WARNINGF(118, parentKey, "illegal number of columns in line %lu", lineCounter);
        }
        ++lineCounter;
    }
    key = keyDup(parentKey);
    keySetString(key, keyBaseName(dirKey));
    ksAppendKey(returned, key);
    keyDel(dirKey);
    fclose(fp);
    elektraFree(lineBuffer);
    ksDel(header);
    return 1;
}
Ejemplo n.º 19
0
/**
 * Load a plugin.
 *
 * The array of plugins must be set to 0.
 * Its length is NR_OF_PLUGINS.
 *
 * systemConfig will only be used, not deleted.
 *
 * @param config the config with the information how the
 *        plugins should be put together
 * @param systemConfig the shared (system) config for the plugins.
 *        Every plugin additional get this config.
 *
 * @retval -1 on failure
 */
int elektraProcessPlugins (Plugin ** plugins, KeySet * modules, KeySet * referencePlugins, KeySet * config, KeySet * systemConfig,
			   Key * errorKey)
{
	Key * root;
	Key * cur;

	ksRewind (config);

	root = ksNext (config);

	while ((cur = ksNext (config)) != 0)
	{
		if (keyRel (root, cur) == 1)
		{
			char * pluginName = 0;
			char * referenceName = 0;
			int pluginNumber = 0;

			Key * key;

			if (elektraProcessPlugin (cur, &pluginNumber, &pluginName, &referenceName, errorKey) == -1)
			{
				elektraFree (pluginName);
				elektraFree (referenceName);
				ksDel (config);
				return -1;
			}


			if (pluginName)
			{
				key = keyDup (cur);
				keyAddBaseName (key, "config");
				KeySet * cutConfig = ksCut (config, key);
				keyDel (key);

				KeySet * pluginConfig = elektraRenameKeys (cutConfig, "user");
				ksDel (cutConfig);
				if (!pluginConfig) return -1;
				ksAppend (pluginConfig, systemConfig);
				ksRewind (pluginConfig); /* TODO: bug ksAppend invalidates cursor */

				/* case 1, we create a new plugin,
				   note that errorKey is not passed here, because it would set error information
				   but we only want a warning instead. */
				plugins[pluginNumber] = elektraPluginOpen (pluginName, modules, pluginConfig, errorKey);
				if (!plugins[pluginNumber])
				{
					ELEKTRA_ADD_WARNING (64, errorKey, pluginName);
					/* Loading plugin did not work */
					elektraFree (pluginName);
					elektraFree (referenceName);
					ksDel (config);
					return -1;
				}

				/* case 2, we label it for later use */
				if (referenceName)
					ksAppendKey (referencePlugins,
						     keyNew (referenceName, KEY_BINARY, KEY_SIZE, sizeof (plugins[pluginNumber]), KEY_VALUE,
							     &plugins[pluginNumber], KEY_END));
			}
			else
			{
				/* case 3, we use an existing plugin */
				Key * lookup = ksLookup (referencePlugins, keyNew (referenceName, KEY_END), KDB_O_DEL);
				if (!lookup)
				{
					ELEKTRA_ADD_WARNING (65, errorKey, referenceName);
					/* Getting a reference plugin at a previous stage did not work.
					Note that this check is necessary, because loading the plugin could
					fail for example at errorplugins and at a later point, for example
					at setplugins it is tried to refer to that.*/
					elektraFree (referenceName);
					ksDel (config);
					return -1;
				}
				plugins[pluginNumber] = *(Plugin **)keyValue (lookup);
				++plugins[pluginNumber]->refcounter;
			}
			elektraFree (pluginName);
			elektraFree (referenceName);
		}
		else
		{
			ELEKTRA_ADD_WARNING (21, errorKey, keyString (cur));
		}
	}

	ksDel (config);
	return 0;
}
Ejemplo n.º 20
0
/**
 * Opens a plugin.
 *
 * The config will be used as is. So be sure to transfer ownership
 * of the config to it, with e.g. ksDup().
 * elektraPluginClose() will delete the config.
 *
 * @return a pointer to a new created plugin or 0 on error
 */
Plugin * elektraPluginOpen (const char * name, KeySet * modules, KeySet * config, Key * errorKey)
{
	Plugin * handle = 0;
	const char * n;

	elektraPluginFactory pluginFactory = 0;

	if (!name || name[0] == '\0')
	{
		ELEKTRA_ADD_WARNING (39, errorKey, "name is null or empty");
		goto err_clup;
	}

	n = name;
	while (*n != '\0')
	{
		if (*n == '/')
			++n;
		else
			break;
	}

	if (*n == '\0')
	{
		ELEKTRA_ADD_WARNING (39, errorKey, "name contained slashes only");
		goto err_clup;
	}

	pluginFactory = elektraModulesLoad (modules, name, errorKey);
	if (pluginFactory == 0)
	{
		/* warning already set by elektraModulesLoad */
		goto err_clup;
	}

	handle = pluginFactory ();
	if (handle == 0)
	{
		ELEKTRA_ADD_WARNING (6, errorKey, name);
		goto err_clup;
	}

	/* init reference counting */
	handle->refcounter = 1;
	handle->config = config;
	config = 0; // for err_clup case

	/* let the plugin initialize itself */
	if (handle->kdbOpen)
	{
		if ((handle->kdbOpen (handle, errorKey)) == -1)
		{
			ELEKTRA_ADD_WARNING (11, errorKey, name);
			elektraPluginClose (handle, errorKey);
			goto err_clup;
		}
	}

#if DEBUG && VERBOSE
	printf ("Finished loading plugin %s\n", name);
#endif
	return handle;

err_clup:
#if DEBUG
	printf ("Failed to load plugin %s\n", name);
#endif
	ksDel (config);
	return 0;
}
Ejemplo n.º 21
0
/**Builds a backend out of the configuration supplied
 * from:
 *
@verbatim
system/elektra/mountpoints/<name>
@endverbatim
 *
 * The root key must be like the above example. You do
 * not need to rewind the keyset. But every key must be
 * below the root key.
 *
 * The internal consistency will be checked in this
 * function. If necessary parts are missing, like
 * no plugins, they cant be loaded or similar 0
 * will be returned.
 *
 * ksCut() is perfectly suitable for cutting out the
 * configuration like needed.
 *
 * @note The given KeySet will be deleted within the function,
 * don't use it afterwards.
 *
 * @param elektraConfig the configuration to work with.
 *        It is used to build up this backend.
 * @param modules used to load new modules or get references
 *        to existing one
 * @param errorKey the key where an error and warnings are added
 *
 * @return a pointer to a freshly allocated backend
 *         this could be the requested backend or a so called
 *         "missing backend".
 * @retval 0 if out of memory
 * @ingroup backend
 */
Backend* elektraBackendOpen(KeySet *elektraConfig, KeySet *modules, Key *errorKey)
{
	Key * cur;
	KeySet *referencePlugins = 0;
	KeySet *systemConfig = 0;
	int failure = 0;

	referencePlugins = ksNew(0, KS_END);
	ksRewind(elektraConfig);

	Key * root = ksNext (elektraConfig);

	Backend *backend = elektraBackendAllocate();
	if (elektraBackendSetMountpoint(backend, elektraConfig, errorKey) == -1)
	{	// warning already set
		failure = 1;
	}

	while ((cur = ksNext(elektraConfig)) != 0)
	{
		if (keyRel (root, cur) == 1)
		{
			// direct below root key
			KeySet *cut = ksCut (elektraConfig, cur);
			if (!strcmp(keyBaseName(cur), "config"))
			{
				systemConfig = elektraRenameKeys(cut, "system");
				ksDel (cut);
			}
			else if (!strcmp(keyBaseName(cur), "errorplugins"))
			{
				if (elektraProcessPlugins(backend->errorplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for error failed");
					failure = 1;
				}
			}
			else if (!strcmp(keyBaseName(cur), "getplugins"))
			{
				if (elektraProcessPlugins(backend->getplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(13, errorKey, "elektraProcessPlugins for get failed");
					failure = 1;
				}
			}
			else if (!strcmp(keyBaseName(cur), "mountpoint"))
			{
				ksDel (cut); // already handled by elektraBackendSetMountpoint
				continue;
			}
			else if (!strcmp(keyBaseName(cur), "setplugins"))
			{
				if (elektraProcessPlugins(backend->setplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for set failed");
					failure = 1;
				}
			} else {
				// no one cares about that config
				if (!failure) ELEKTRA_ADD_WARNING(16, errorKey, keyBaseName(cur));
				ksDel (cut);
			}
		}
	}

	if (failure)
	{
		Backend *tmpBackend = elektraBackendOpenMissing(backend->mountpoint);
		elektraBackendClose(backend, errorKey);
		backend = tmpBackend;
	}

	ksDel (systemConfig);
	ksDel (elektraConfig);
	ksDel (referencePlugins);

	return backend;
}
Ejemplo n.º 22
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 */
}
Ejemplo n.º 23
0
/**
 * @retval 1 and an allocated string of the pluginName if a new plugins should be created.
 * @retval 2 and an allocated string of the referenceName if an old plugin should be used
 * @retval 3 and both if a new plugin should be created and made available for later
 *         back referencing.
 * @retval -1 on error
 */
int elektraProcessPlugin (Key * cur, int * pluginNumber, char ** pluginName, char ** referenceName, Key * errorKey)
{
	const char * fullname = keyBaseName (cur);
	size_t fullsize = keyGetBaseNameSize (cur);

	if (fullname[0] != '#')
	{
		ELEKTRA_ADD_WARNING (18, errorKey, fullname);
		return -1;
	}
	if (fullname[1] < '0' || fullname[1] > '9')
	{
		ELEKTRA_ADD_WARNING (19, errorKey, fullname);
		return -1;
	}
	*pluginNumber = fullname[1] - '0';
	if (*pluginNumber > NR_OF_PLUGINS)
	{
		ELEKTRA_ADD_WARNING (20, errorKey, fullname);
		return -1;
	}

	if (fullname[2] == '#')
	{
		char prefixReferenceName[] = "system/elektra/plugins/";

		/* We have a back reference here */
		if (fullname[fullsize - 2] == '#')
		{
			const char * iter = &fullname[3];
			size_t pluginNameSize = 1; /* For null character */
			size_t referenceNameSize = 0;
			/* We will introduce a new plugin */
			while (*iter != '#')
			{
				++iter;
				++pluginNameSize;
			}

			*pluginName = elektraMalloc (pluginNameSize);
			strncpy (*pluginName, &fullname[3], pluginNameSize);
			(*pluginName)[pluginNameSize - 1] = 0;

			referenceNameSize = fullsize - pluginNameSize - 4;
			++iter; /* advance to one after hash */
			*referenceName = elektraMalloc (referenceNameSize + sizeof (prefixReferenceName));
			strncpy (*referenceName, prefixReferenceName, sizeof (prefixReferenceName));
			strncat (*referenceName, iter, referenceNameSize);
			(*referenceName)[referenceNameSize + sizeof (prefixReferenceName) - 2] = 0;

			return 3;
		}
		else
		{
			/* We reference back to a plugin */

			*referenceName = elektraMalloc (fullsize - 3 + sizeof (prefixReferenceName) - 1);
			strncpy (*referenceName, prefixReferenceName, sizeof (prefixReferenceName));
			strncat (*referenceName, &fullname[3], fullsize - 3);

			return 2;
		}
	}
	else
	{
		*pluginName = elektraMalloc (fullsize - 2); /* don't alloc for #n */
		strncpy (*pluginName, &fullname[2], fullsize - 2);

		return 1;
	}

	/* Should not be reached */
	return 0;
}