Esempio n. 1
0
/* copy the variables to shm mem */
int cfg_shmize(void)
{
	cfg_group_t	*group;
	cfg_block_t	*block = NULL;
	int	size;

	if (!cfg_group) return 0;

	/* Let us allocate one memory block that
	will contain all the variables */
	for (	size=0, group = cfg_group;
		group;
		group=group->next
	) {
		size = ROUND_POINTER(size);
		group->offset = size;
		size += group->size;
	}

	block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1);
	if (!block) {
		LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
		goto error;
	}
	memset(block, 0, sizeof(cfg_block_t)+size-1);
	cfg_block_size = size;

	/* copy the memory fragments to the single block */
	for (	group = cfg_group;
		group;
		group=group->next
	) {
		if (group->dynamic == 0) {
			/* clone the strings to shm mem */
			if (cfg_shmize_strings(group)) goto error;

			/* copy the values to the new block */
			memcpy(block->vars+group->offset, group->vars, group->size);
		} else {
			/* The group was declared with NULL values,
			 * we have to fix it up.
			 * The fixup function takes care about the values,
			 * it fills up the block */
			if (cfg_script_fixup(group, block->vars+group->offset)) goto error;

			/* Notify the drivers about the new config definition.
			 * Temporary set the group handle so that the drivers have a chance to
			 * overwrite the default values. The handle must be reset after this
			 * because the main process does not have a local configuration. */
			*(group->handle) = block->vars+group->offset;
			cfg_notify_drivers(group->name, group->name_len,
					group->mapping->def);
			*(group->handle) = NULL;
		}
	}
	/* try to fixup the selects that failed to be fixed-up previously */
	if (cfg_fixup_selects()) goto error;

	/* install the new config */
	cfg_install_global(block, NULL, NULL, NULL);
	cfg_shmized = 1;

	return 0;

error:
	if (block) shm_free(block);
	return -1;
}
Esempio n. 2
0
/* commits the previously prepared changes within the context */
int cfg_commit(cfg_ctx_t *ctx)
{
	int	replaced_num = 0;
	cfg_changed_var_t	*changed, *changed2;
	cfg_block_t	*block;
	char	**replaced = NULL;
	cfg_child_cb_t	*child_cb;
	cfg_child_cb_t	*child_cb_first = NULL;
	cfg_child_cb_t	*child_cb_last = NULL;
	int	size;
	void	*p;
	str	s, s2;

	if (!ctx) {
		LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
		return -1;
	}

	if (!cfg_shmized) return 0; /* nothing to do */

	/* the ctx must be locked while reading and writing
	the list of changed variables */
	CFG_CTX_LOCK(ctx);

	/* is there any change? */
	if (!ctx->changed_first) goto done;

	/* count the number of replaced strings,
	and prepare the linked list of per-child process
	callbacks, that will be added to the global list */
	for (	changed = ctx->changed_first;
		changed;
		changed = changed->next
	) {
		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
		|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
			replaced_num++;


		if (changed->var->def->on_set_child_cb) {
			s.s = changed->group->name;
			s.len = changed->group->name_len;
			s2.s = changed->var->def->name;
			s2.len = changed->var->name_len;
			child_cb = cfg_child_cb_new(&s, &s2,
					changed->var->def->on_set_child_cb,
					changed->var->def->type);
			if (!child_cb) goto error0;

			if (child_cb_last)
				child_cb_last->next = child_cb;
			else
				child_cb_first = child_cb;
			child_cb_last = child_cb;
		}
	}

	if (replaced_num) {
		/* allocate memory for the replaced string array */
		size = sizeof(char *)*(replaced_num + 1);
		replaced = (char **)shm_malloc(size);
		if (!replaced) {
			LOG(L_ERR, "ERROR: cfg_commit(): not enough shm memory\n");
			goto error;
		}
		memset(replaced, 0 , size);
	}

	/* make sure that nobody else replaces the global config
	while the new one is prepared */
	CFG_WRITER_LOCK();

	/* clone the memory block, and prepare the modification */
	if (!(block = cfg_clone_global())) {
		CFG_WRITER_UNLOCK();
		goto error;
	}

	/* apply the modifications to the buffer */
	replaced_num = 0;
	for (	changed = ctx->changed_first;
		changed;
		changed = changed->next
	) {
		p = block->vars
			+ changed->group->offset
			+ changed->var->offset;

		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
		|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
			replaced[replaced_num] = *(char **)p;
			if (replaced[replaced_num])
				replaced_num++;
			/* else do not increase replaced_num, because
			the cfg_block_free() will stop at the first
			NULL value */
		}

		memcpy(	p,
			changed->new_val.vraw,
			cfg_var_size(changed->var));
	}

	/* replace the global config with the new one */
	cfg_install_global(block, replaced, child_cb_first, child_cb_last);
	CFG_WRITER_UNLOCK();

	/* free the changed list */	
	for (	changed = ctx->changed_first;
		changed;
		changed = changed2
	) {
		changed2 = changed->next;
		shm_free(changed);
	}
	ctx->changed_first = NULL;
	ctx->changed_last = NULL;

done:
	LOG(L_INFO, "INFO: cfg_commit(): config changes have been applied "
			"[context=%p]\n",
			ctx);

	CFG_CTX_UNLOCK(ctx);
	return 0;

error:
	CFG_CTX_UNLOCK(ctx);

error0:

	if (child_cb_first) cfg_child_cb_free(child_cb_first);
	if (replaced) shm_free(replaced);

	return -1;
}
Esempio n. 3
0
/* copy the variables to shm mem */
int cfg_shmize(void)
{
	cfg_group_t	*group;
	cfg_block_t	*block = NULL;
	int	size;

	if (!cfg_group) return 0;

	/* Let us allocate one memory block that
	 * will contain all the variables + meta-data
	 * in the following form:
	 * |-----------|
	 * | meta-data | <- group A: meta_offset
	 * | variables | <- group A: var_offset
	 * |-----------|
	 * | meta-data | <- group B: meta_offset
	 * | variables | <- group B: var_offset
	 * |-----------|
	 * |    ...    |
	 * |-----------|
	 *
	 * The additional array for the multiple values
	 * of the same variable is linked to the meta-data.
	 */
	for (	size=0, group = cfg_group;
		group;
		group=group->next
	) {
		size = ROUND_POINTER(size);
		group->meta_offset = size;
		size += sizeof(cfg_group_meta_t);

		size = ROUND_POINTER(size);
		group->var_offset = size;
		size += group->size;
	}

	block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1);
	if (!block) {
		LOG(L_ERR, "ERROR: cfg_shmize(): not enough shm memory\n");
		goto error;
	}
	memset(block, 0, sizeof(cfg_block_t)+size-1);
	cfg_block_size = size;

	/* copy the memory fragments to the single block */
	for (	group = cfg_group;
		group;
		group=group->next
	) {
		if (group->dynamic == CFG_GROUP_STATIC) {
			/* clone the strings to shm mem */
			if (cfg_shmize_strings(group)) goto error;

			/* copy the values to the new block */
			memcpy(CFG_GROUP_DATA(block, group), group->vars, group->size);
		} else if (group->dynamic == CFG_GROUP_DYNAMIC) {
			/* The group was declared with NULL values,
			 * we have to fix it up.
			 * The fixup function takes care about the values,
			 * it fills up the block */
			if (cfg_script_fixup(group, CFG_GROUP_DATA(block, group))) goto error;

			/* Notify the drivers about the new config definition.
			 * Temporary set the group handle so that the drivers have a chance to
			 * overwrite the default values. The handle must be reset after this
			 * because the main process does not have a local configuration. */
			*(group->handle) = CFG_GROUP_DATA(block, group);
			cfg_notify_drivers(group->name, group->name_len,
					group->mapping->def);
			*(group->handle) = NULL;
		} else {
			LOG(L_ERR, "ERROR: cfg_shmize(): Configuration group is declared "
					"without any variable: %.*s\n",
					group->name_len, group->name);
			goto error;
		}

		/* Create the additional group instances with applying
		the temporary list. */
		if (apply_add_var_list(block, group))
			goto error;
	}

	/* try to fixup the selects that failed to be fixed-up previously */
	if (cfg_fixup_selects()) goto error;

	/* install the new config */
	cfg_install_global(block, NULL, NULL, NULL);
	cfg_shmized = 1;

	return 0;

error:
	if (block) shm_free(block);
	return -1;
}
Esempio n. 4
0
/* sets the value of a variable without the need of commit
 *
 * return value:
 *   0: success
 *  -1: error
 *   1: variable has not been found
 */
int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
			void *val, unsigned int val_type)
{
	cfg_group_t	*group;
	cfg_mapping_t	*var;
	void		*p, *v;
	cfg_block_t	*block = NULL;
	str		s, s2;
	char		*old_string = NULL;
	char		**replaced = NULL;
	cfg_child_cb_t	*child_cb = NULL;

	/* verify the context even if we do not need it now
	to make sure that a cfg driver has called the function
	(very very weak security) */
	if (!ctx) {
		LOG(L_ERR, "ERROR: cfg_set_now(): context is undefined\n");
		return -1;
	}

	/* look-up the group and the variable */
	if (cfg_lookup_var(group_name, var_name, &group, &var))
		return 1;
		
	/* check whether the variable is read-only */
	if (var->def->type & CFG_READONLY) {
		LOG(L_ERR, "ERROR: cfg_set_now(): variable is read-only\n");
		goto error0;
	}

	/* check whether we have to convert the type */
	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
		goto error0;
	
	if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
	&& (var->def->min || var->def->max)) {
		/* perform a simple min-max check for integers */
		if (((int)(long)v < var->def->min)
		|| ((int)(long)v > var->def->max)) {
			LOG(L_ERR, "ERROR: cfg_set_now(): integer value is out of range\n");
			goto error0;
		}
	}

	if (var->def->on_change_cb) {
		/* Call the fixup function.
		There is no need to set a temporary cfg handle,
		becaue a single variable is changed */
		if (var->def->on_change_cb(*(group->handle),
						group_name,
						var_name,
						&v) < 0) {
			LOG(L_ERR, "ERROR: cfg_set_now(): fixup failed\n");
			goto error0;
		}

	}

	if (var->def->on_set_child_cb) {
		/* get the name of the variable from the internal struct,
		because var_name may be freed before the callback needs it */
		s.s = group->name;
		s.len = group->name_len;
		s2.s = var->def->name;
		s2.len = var->name_len;
		child_cb = cfg_child_cb_new(&s, &s2,
					var->def->on_set_child_cb,
					var->def->type);
		if (!child_cb) {
			LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
			goto error0;
		}
	}

	if (cfg_shmized) {
		/* make sure that nobody else replaces the global config
		while the new one is prepared */
		CFG_WRITER_LOCK();

		if (var->def->type & CFG_ATOMIC) {
			/* atomic change is allowed, we can rewrite the value
			directly in the global config */
			p = (*cfg_global)->vars+group->offset+var->offset;

		} else {
			/* clone the memory block, and prepare the modification */
			if (!(block = cfg_clone_global())) goto error;

			p = block->vars+group->offset+var->offset;
		}
	} else {
		/* we are allowed to rewrite the value on-the-fly
		The handle either points to group->vars, or to the
		shared memory block (dynamic group) */
		p = *(group->handle) + var->offset;
	}

	/* set the new value */
	switch (CFG_VAR_TYPE(var)) {
	case CFG_VAR_INT:
		*(int *)p = (int)(long)v;
		break;

	case CFG_VAR_STRING:
		/* clone the string to shm mem */
		s.s = v;
		s.len = (s.s) ? strlen(s.s) : 0;
		if (cfg_clone_str(&s, &s)) goto error;
		old_string = *(char **)p;
		*(char **)p = s.s;
		break;

	case CFG_VAR_STR:
		/* clone the string to shm mem */
		s = *(str *)v;
		if (cfg_clone_str(&s, &s)) goto error;
		old_string = *(char **)p;
		memcpy(p, &s, sizeof(str));
		break;

	case CFG_VAR_POINTER:
		*(void **)p = v;
		break;

	}

	if (cfg_shmized) {
		if (old_string) {
			/* prepare the array of the replaced strings,
			they will be freed when the old block is freed */
			replaced = (char **)shm_malloc(sizeof(char *)*2);
			if (!replaced) {
				LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
				goto error;
			}
			replaced[0] = old_string;
			replaced[1] = NULL;
		}
		/* replace the global config with the new one */
		if (block) cfg_install_global(block, replaced, child_cb, child_cb);
		CFG_WRITER_UNLOCK();
	} else {
		/* cfg_set() may be called more than once before forking */
		if (old_string && (var->flag & cfg_var_shmized))
			shm_free(old_string);

		/* flag the variable because there is no need
		to shmize it again */
		var->flag |= cfg_var_shmized;

		/* the global config does not have to be replaced,
		but the child callback has to be installed, otherwise the
		child processes will miss the change */
		if (child_cb)
			cfg_install_child_cb(child_cb, child_cb);
	}

	if (val_type == CFG_VAR_INT)
		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
			"has been changed to %d\n",
			group_name->len, group_name->s,
			var_name->len, var_name->s,
			(int)(long)val);

	else if (val_type == CFG_VAR_STRING)
		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
			"has been changed to \"%s\"\n",
			group_name->len, group_name->s,
			var_name->len, var_name->s,
			(char *)val);

	else /* str type */
		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
			"has been changed to \"%.*s\"\n",
			group_name->len, group_name->s,
			var_name->len, var_name->s,
			((str *)val)->len, ((str *)val)->s);

	convert_val_cleanup();
	return 0;

error:
	if (cfg_shmized) CFG_WRITER_UNLOCK();
	if (block) cfg_block_free(block);
	if (child_cb) cfg_child_cb_free(child_cb);

error0:
	LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
			group_name->len, group_name->s,
			var_name->len, var_name->s);


	convert_val_cleanup();
	return -1;
}