Exemple #1
0
/**
 * Allocates a new split object.
 *
 * Splits up a keyset into multiple keysets where each
 * of them will passed to the correct kdbSet().
 *
 * Initially the size is 0 and alloc is APPROXIMATE_NR_OF_BACKENDS.
 *
 * @return a fresh allocated split object
 * @ingroup split
 * @see elektraSplitDel()
**/
Split * elektraSplitNew (void)
{
	Split * ret = elektraCalloc (sizeof (Split));

	ret->size = 0;
	ret->alloc = APPROXIMATE_NR_OF_BACKENDS;

	ret->keysets = elektraCalloc (sizeof (KeySet *) * ret->alloc);
	ret->handles = elektraCalloc (sizeof (KDB *) * ret->alloc);
	ret->parents = elektraCalloc (sizeof (Key *) * ret->alloc);
	ret->syncbits = elektraCalloc (sizeof (int) * ret->alloc);

	return ret;
}
Exemple #2
0
static void test_elektraMalloc (void)
{
	char * buffer = 0;
	buffer = elektraMalloc (50);
	exit_if_fail (buffer, "buffer must not be 0 after allocation");
	elektraRealloc ((void **)&buffer, 100);
	exit_if_fail (buffer, "buffer must not be 0 after reallocation");
	elektraRealloc ((void **)&buffer, 20);
	exit_if_fail (buffer, "buffer must not be 0 after reallocation");
	elektraFree (buffer);

	buffer = elektraCalloc (50);
	exit_if_fail (buffer, "buffer must not be 0 after allocation");
	for (int i = 0; i < 50; ++i)
	{
		succeed_if (buffer[i] == 0, "elektraCalloc did not initialize buffer with zeros");
	}
	elektraRealloc ((void **)&buffer, 100);
	exit_if_fail (buffer, "buffer must not be 0 after reallocation");
	elektraRealloc ((void **)&buffer, 20);
	exit_if_fail (buffer, "buffer must not be 0 after reallocation");

	char * dup = elektraStrNDup (buffer, 20);
	exit_if_fail (dup, "could not duplicate buffer");
	elektraFree (buffer);
	buffer = 0;
	for (int i = 0; i < 20; ++i)
	{
		succeed_if (dup[i] == 0, "elektraStrNDup did not correctly copy zero-buffer");
	}
	elektraFree (dup);
}
Trie *test_insert (Trie *trie, char *name, char* value)
{
	Backend *backend = elektraCalloc (sizeof (Backend));
	backend->mountpoint = keyNew (name, KEY_VALUE, value, KEY_END);
	backend->refcounter = 1;
	keyIncRef (backend->mountpoint);
	return elektraTrieInsert(trie, name, backend);
}
/**
 * Creates a new ElektraError using the provided values.
 * The returned value will be allocated with elektraCalloc().
 *
 * @param code        The error code of the error.
 * @param description The description of the error.
 * @param severity    The severity of the error. Only use ELEKTRA_ERROR_SEVERITY_FATAL,
 *                    if the error will be raised with elektraFatalError().
 * @param group       The group to which this error belongs.
 * @param module      The module from which this error originates.
 * @return A newly allocated ElektraError (free with elektraFree()).
 */
ElektraError * elektraErrorCreate (ElektraErrorCode code, const char * description, ElektraErrorSeverity severity)
{
	ElektraError * const error = elektraCalloc (sizeof (struct _ElektraError));
	error->code = code;
	error->description = elektraStrDup (description);
	error->severity = severity;

	return error;
}
Exemple #5
0
ssize_t elektraFinalizeEmptyName (Key * key)
{
	key->key = elektraCalloc (2); // two null pointers
	key->keySize = 1;
	key->keyUSize = 1;
	key->flags |= KEY_FLAG_SYNC;

	return key->keySize;
}
Backend *b_new(const char *name, const char *value)
{
	Backend *backend = elektraCalloc (sizeof (Backend));
	backend->refcounter = 1;

	backend->mountpoint = keyNew (name, KEY_VALUE, value, KEY_END);
	keyIncRef (backend->mountpoint);

	return backend;
}
Exemple #7
0
/**
 * @internal
 * Create new data structure for binding operations.
 *
 * @return  new data structure
 */
static UvBindingData * newBindingData (void)
{
	UvBindingData * bindingData = elektraCalloc (sizeof (*bindingData));
	if (bindingData == NULL)
	{
		ELEKTRA_LOG_WARNING ("elektraCalloc failed");
		return NULL;
	}

	return bindingData;
}
Exemple #8
0
/**
 * @brief Allocate a backend
 *
 * Initialize everything with zero, except: sizes with -1
 * and refcounter with 1
 *
 * @return 
 */
static Backend* elektraBackendAllocate()
{
	Backend *backend = elektraCalloc(sizeof(struct _Backend));

	backend->refcounter = 1;

	backend->specsize = -1;
	backend->dirsize = -1;
	backend->usersize = -1;
	backend->systemsize = -1;
	return backend;
}
Exemple #9
0
static void elektraGenTempFilename (ElektraResolved * handle, ElektraResolveTempfile tmpDir)
{
	char * tmpFile = NULL;
	size_t len = 0;
	size_t tmpFilenameSize = 0;
	if (tmpDir == ELEKTRA_RESOLVER_TEMPFILE_SAMEDIR)
	{
		tmpFilenameSize = strlen (handle->fullPath) + POSTFIX_SIZE;
		tmpFile = elektraCalloc (tmpFilenameSize);
		len = sprintf (tmpFile, "%s", handle->fullPath);
	}
	else if (tmpDir == ELEKTRA_RESOLVER_TEMPFILE_TMPDIR)
	{
		tmpFilenameSize = sizeof ("/tmp/") + strlen (handle->fullPath) + POSTFIX_SIZE;
		tmpFile = elektraCalloc (tmpFilenameSize);
		len = sprintf (tmpFile, "/tmp/%s", handle->fullPath);
	}

	struct timeval tv;
	memset (&tv, 0, sizeof (struct timeval));
	gettimeofday (&tv, 0);
	snprintf (tmpFile + len, POSTFIX_SIZE - 1, ".%d:%ld." ELEKTRA_TIME_USEC_F ".tmp", getpid (), tv.tv_sec, tv.tv_usec);
	handle->tmpFile = tmpFile;
}
Exemple #10
0
static void genCheckoutFileName (GitData * data)
{
	// generate temp filename: /tmp/branch_filename_tv_sec:tv_usec
	struct timeval tv;
	gettimeofday (&tv, 0);
	const char * fileName = strrchr (data->file, '/');
	if (!fileName)
		fileName = data->file;
	else
		fileName += 1;
	size_t len = strlen (DEFAULT_CHECKOUT_LOCATION) + strlen (data->branch) + strlen (fileName) + TV_MAX_DIGITS + 1;
	data->tmpFile = elektraCalloc (len);
	snprintf (data->tmpFile, len, "%s%s_%s_%lu:" ELEKTRA_TIME_USEC_F, DEFAULT_CHECKOUT_LOCATION, data->branch, fileName, tv.tv_sec,
		  tv.tv_usec);
}
Exemple #11
0
/**
 * @brief Allows one to Export Methods for a Plugin.
 *
 * This function must be called within ELEKTRA_PLUGIN_EXPORT.
 * It define the plugin's methods that will be exported.
 *
 * All KDB methods implemented by the plugin basically could
 * have random names (convention is elektraName*), except
 * ELEKTRA_PLUGIN_EXPORT.
 *
 * This is the single symbol that will be looked up
 * when loading the plugin, and the first method of the backend
 * implementation that will be called.
 *
 * You need to use a macro so that both dynamic and static loading
 * of the plugin works. For example for the doc plugin:
 * @snippet doc.c export
 *
 * The first parameter is the name of the plugin.
 * Then every plugin should have:
 * @c ELEKTRA_PLUGIN_OPEN,
 * @c ELEKTRA_PLUGIN_CLOSE,
 * @c ELEKTRA_PLUGIN_GET,
 * @c ELEKTRA_PLUGIN_SET and optionally
 * @c ELEKTRA_PLUGIN_ERROR.
 *
 * The list is terminated with
 * @c ELEKTRA_PLUGIN_END.
 *
 * You must use static "char arrays" in a read only segment.
 * Don't allocate storage, it won't be freed.
 *
 * @param pluginName the name of this plugin
 * @return an object that contains all plugin information needed by
 * 	libelektra.so
 * @ingroup plugin
 */
Plugin * elektraPluginExport (const char * pluginName, ...)
{
	va_list va;
	Plugin * returned;
	plugin_t method = 0;

	if (pluginName == 0) return 0;

	returned = elektraCalloc (sizeof (struct _Plugin));

	/* Start processing parameters */
	va_start (va, pluginName);
	returned->name = pluginName;

	while ((method = va_arg (va, plugin_t)))
	{
		switch (method)
		{
		case ELEKTRA_PLUGIN_OPEN:
			returned->kdbOpen = va_arg (va, kdbOpenPtr);
			break;
		case ELEKTRA_PLUGIN_CLOSE:
			returned->kdbClose = va_arg (va, kdbClosePtr);
			break;
		case ELEKTRA_PLUGIN_GET:
			returned->kdbGet = va_arg (va, kdbGetPtr);
			break;
		case ELEKTRA_PLUGIN_SET:
			returned->kdbSet = va_arg (va, kdbSetPtr);
			break;
		case ELEKTRA_PLUGIN_ERROR:
			returned->kdbError = va_arg (va, kdbErrorPtr);
			break;
		default:
			ELEKTRA_ASSERT (0, "plugin passed something unexpected");
		// fallthrough, will end here
		case ELEKTRA_PLUGIN_END:
			va_end (va);
			return returned;
		}
	}
	return returned;
}
Exemple #12
0
Trie* elektraTrieInsert(Trie *trie, const char *name, Backend *value)
{
	char* p;
	unsigned char idx;

	if (name==0) name="";
	idx=(unsigned char)name[0];

	if (trie==NULL)
	{
		trie=elektraCalloc(sizeof(Trie));

		if (!strcmp("",name))
		{
			trie->empty_value=value;
			return trie;
		}

		trie->textlen[idx]=strlen(name);

		trie->text[idx]=elektraStrDup(name);

		trie->value[idx]=value;
		return trie;
	}

	if (!strcmp("",name))
	{
		trie->empty_value=value;
		return trie;
	}

	if (trie->text[idx]) {
		/* there exists an entry with the same first character */
		if ((p=elektraTrieStartsWith(name, trie->text[idx]))==0)
		{
			/* the name in the trie is part of the searched name --> continue search */
			trie->children[idx]=elektraTrieInsert(trie->children[idx],name+trie->textlen[idx],value);
		} else {
			/* name in trie doesn't match name --> split trie */
			char *newname;
			Trie *child;
			unsigned char idx2;

			newname=elektraStrDup(p);
			*p=0; /* shorten the old name in the trie */
			trie->textlen[idx]=strlen(trie->text[idx]);

			child=trie->children[idx];

			/* insert the name given as a parameter into the new trie entry */
			trie->children[idx]=elektraTrieInsert(NULL, name+(p-trie->text[idx]), value);

			/* insert the split try into the new trie entry */

			idx2 = (unsigned char) newname[0];
			trie->children[idx]->text[idx2]=newname;
			trie->children[idx]->textlen[idx2]=strlen(newname);
			trie->children[idx]->value[idx2]=trie->value[idx];
			trie->children[idx]->children[idx2]=child;

			trie->value[idx]=0;

		}
	} else {
		/* there doesn't exist an entry with the same first character */
		trie->text[idx]=elektraStrDup(name);
		trie->value[idx]=(void*)value;
		trie->textlen[idx]=strlen(name);
	}

	return trie;
}
KDB* kdb_new()
{
	KDB *kdb = elektraCalloc (sizeof (KDB));
	kdb->split = elektraSplitNew();
	return kdb;
}
Exemple #14
0
int elektraSortTopology (KeySet * ks, Key ** array)
{
	if (ks == NULL || array == NULL) return -1;
	KeySet * done = ksNew (0, KS_END);
	ksRewind (ks);
	Key * cur;
	ssize_t size = ksGetSize (ks);
	Key * orderCounter = keyNew ("/#", KEY_CASCADING_NAME, KEY_END);
	elektraArrayIncName (orderCounter);
	_adjMatrix adjMatrix[size];
	int i = 0;
	int retVal = 1;
	int depCount = 0;
	Key ** localArray = elektraMalloc (size * sizeof (Key *));
	elektraKsToMemArray (ks, localArray);
	qsort (localArray, size, sizeof (Key *), topCmpOrder);
	for (long j = 0; j < size; ++j)
	{
		adjMatrix[j].key = localArray[j];
		adjMatrix[j].isResolved = 0;
		adjMatrix[j].deps = elektraCalloc (sizeof (unsigned long) * size);
	}
	kdb_octet_t hasOrder = 0;
	if (keyGetMeta (localArray[0], "order")) hasOrder = 1;
	unsigned int unresolved = 0;
	for (int j = 0; j < size; ++j)
	{
		cur = localArray[j];
		KeySet * deps = elektraMetaArrayToKS (cur, "dep");
		keyDel (ksLookupByName (deps, "dep", KDB_O_POP));
		Key * tmpDep;
		switch (ksGetSize (deps))
		{
		case -1:
		{
			// key has no dependencies, give it an order number and add it to list of resolved dependencies
			keySetMeta (cur, "order", keyBaseName (orderCounter));
			elektraArrayIncName (orderCounter);
			ksAppendKey (done, keyDup (cur));
			adjMatrix[j].isResolved = 1;
			ksDel (deps);
			break;
		}
		case 1:
		{
			// only 1 dependency:
			// test if it's reflexive
			tmpDep = ksHead (deps);
			if (!strcmp (keyName (cur), keyString (tmpDep)))
			{
				keySetMeta (cur, "order", keyBaseName (orderCounter));
				elektraArrayIncName (orderCounter);
				ksAppendKey (done, keyDup (cur));
				adjMatrix[j].isResolved = 1;
				ksDel (deps);
				break;
			}
			// if not, fallthrough to normal dependency handling
		}
		default:
		{
			int gotUnresolved = 0;
			while ((tmpDep = ksNext (deps)) != NULL)
			{
				if (!isValidKeyName (keyString (tmpDep)))
				{
					// invalid keyname -> ERROR
					retVal = -1;
					break;
				}
				i = getArrayIndex (tmpDep, adjMatrix, size);
				if (i == -1)
				{
					// key doesn't exist yet but has valid name, ignore it.
					continue;
				}
				else if (i == j)
				{
					// reflexiv depencency, do nothing
				}
				else
				{
					if (!adjMatrix[i].isResolved)
					{
						// unresolved dependency
						adjMatrix[j].deps[i] = 1;
						++gotUnresolved;
						// simple cycle detection
						if (adjMatrix[i].deps[j])
						{
							retVal = 0;
							break;
						}
					}
				}
			}
			if (gotUnresolved)
			{
				adjMatrix[j].isResolved = 0;
				++unresolved;
				// cound unresolved dependencies
				depCount += gotUnresolved;
			}
			ksDel (deps);
			break;
		}
		}
		if (retVal <= 0) break;
	}
	if (retVal <= 0)
	{
		// error or cycle: goto cleanup
		goto TopSortCleanup;
	}

	// resolve all dependencies that can be resolved immediately
	for (int j = 0; j < size; ++j)
	{
		if (adjMatrix[j].isResolved) depCount -= resolveDep (j, adjMatrix, size);
	}

	ssize_t resolved = ksGetSize (done);
	if (((depCount + resolved) >= size) && (unresolved))
	{
		// more dependencies dependencies than keys:
		//  cycle found !
		retVal = 0;
		goto TopSortCleanup;
	}

	if (unresolved)
	{
		int found = 1;
		// we have unresolved dependencies
		for (int j = 0; j < size + 1; ++j)
		{
			// loop until no dependency can be resolved anymore
			if (j == size)
			{
				if (found)
				{
					found = 0;
					j = -1;
					unresolved = 0;
					continue;
				}
				else
					break;
			}
			if (adjMatrix[j].isResolved) continue;
			++unresolved;
			if (hasOrder)
			{
				// resolve by order
				int ret = resolveDeps (j, adjMatrix, size, done, orderCounter);
				if (ret == -1) break;
				j = -1;
				found = 1;
				continue;
			}
			else
			{
				// resolve next possible dependency in keyset
				if (!hasUnresolvedDependencies (j, adjMatrix, size))
				{
					adjMatrix[j].isResolved = 1;
					resolveDep (j, adjMatrix, size);
					keySetMeta (localArray[j], "order", keyBaseName (orderCounter));
					elektraArrayIncName (orderCounter);
					ksAppendKey (done, keyDup (localArray[j]));
					found = 1;
				}
			}
		}
	}
	if (unresolved == 0)
	{
		// everything resolved
		// add dependencies in topological order to array
		elektraKsToMemArray (ks, array);
		qsort (array, size, sizeof (Key *), topCmpOrder);
		retVal = 1;
	}
	else
	{
		// still unresolved dependencies left:
		// there must be a cycle somewhere
		retVal = 0;
	}
TopSortCleanup:
	ksDel (done);
	keyDel (orderCounter);
	elektraFree (localArray);
	for (ssize_t j = 0; j < size; ++j)
	{
		elektraFree (adjMatrix[j].deps);
	}
	return retVal;
}
Exemple #15
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;
}