Example #1
0
/* Child process init function that can be called
 * without cfg_register_child().
 * Note that the child process may miss some configuration changes.
 */
int cfg_late_child_init(void)
{
	/* set the callback list pointer to the beginning of the list */
	CFG_LOCK();
	atomic_inc(&((*cfg_child_cb_first)->refcnt));
	cfg_child_cb = *cfg_child_cb_first;
	CFG_UNLOCK();

	return 0;
}
Example #2
0
/* per-child process destroy function
 * Should be called only when the child process exits,
 * but SER continues running
 *
 * WARNING: this function call must be the very last action
 * before the child process exits, because the local config
 * is not available afterwards.
 */
void cfg_child_destroy(void)
{
	cfg_child_cb_t	*prev_cb;

	/* unref the local config */
	if (cfg_local) {
		CFG_UNREF(cfg_local);
		cfg_local = NULL;
	}

	if (!cfg_child_cb || cfg_child_cb==CFG_NO_CHILD_CBS) return;

	/* The lock must be held to make sure that the global config
	is not replaced meantime, and the other child processes do not
	leave the old value of *cfg_child_cb_last. Otherwise it could happen,
	that all the other processes move their own cfg_child_cb pointer before
	this process reaches *cfg_child_cb_last, though, it is very unlikely. */
	CFG_LOCK();

	/* go through the list and check whether there is any item that
	has to be freed (similar to cfg_update_local(), but without executing
	the callback functions) */
	while (cfg_child_cb != *cfg_child_cb_last) {
		prev_cb = cfg_child_cb;
		cfg_child_cb = cfg_child_cb->next;
		atomic_inc(&cfg_child_cb->refcnt);
		if (atomic_dec_and_test(&prev_cb->refcnt)) {
			/* No more pocess refers to this callback.
			Did this process block the deletion,
			or is there any other process that has not
			reached	prev_cb yet? */
			if (*cfg_child_cb_first == prev_cb) {
				/* yes, this process was blocking the deletion */
				*cfg_child_cb_first = cfg_child_cb;
				shm_free(prev_cb);
			}
		} else {
			/* no need to continue, because there is at least
			one process that stays exactly at the same point
			in the list, so it will free the items later */
			break;
		}
	}
	atomic_dec(&cfg_child_cb->refcnt);

	CFG_UNLOCK();
	cfg_child_cb = NULL;
}
Example #3
0
/* installs a new global config
 *
 * replaced is an array of strings that must be freed together
 * with the previous global config.
 * cb_first and cb_last define a linked list of per-child process
 * callbacks. This list is added to the global linked list.
 */
void cfg_install_global(cfg_block_t *block, void **replaced,
			cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
{
	cfg_block_t* old_cfg;
	
	CFG_REF(block);

	if (replaced) {
		/* The replaced array is specified, it has to be linked to the child cb structure.
		 * The last child process processing this structure will free the old strings and the array. */
		if (cb_first) {
			cb_first->replaced = replaced;
		} else {
			/* At least one child cb structure is needed. */
			cb_first = cfg_child_cb_new(NULL, NULL, NULL, 0 /* gname, name, cb, type */);
			if (cb_first) {
				cb_last = cb_first;
				cb_first->replaced = replaced;
			} else {
				LOG(L_ERR, "ERROR: cfg_install_global(): not enough shm memory\n");
				/* Nothing more can be done here, the replaced strings are still needed,
				 * they cannot be freed at this moment.
				 */
			}
		}
	}

	CFG_LOCK();

	old_cfg = *cfg_global;
	*cfg_global = block;

	if (cb_first)
		cfg_install_child_cb(cb_first, cb_last);

	CFG_UNLOCK();
	
	if (old_cfg)
		CFG_UNREF(old_cfg);
}
Example #4
0
/* installs a new global config
 *
 * replaced is an array of strings that must be freed together
 * with the previous global config.
 * cb_first and cb_last define a linked list of per-child process
 * callbacks. This list is added to the global linked list.
 */
void cfg_install_global(cfg_block_t *block, char **replaced,
			cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
{
	cfg_block_t* old_cfg;
	
	CFG_REF(block);

	CFG_LOCK();

	old_cfg = *cfg_global;
	*cfg_global = block;

	if (cb_first)
		cfg_install_child_cb(cb_first, cb_last);

	CFG_UNLOCK();
	
	if (old_cfg) {
		if (replaced) (old_cfg)->replaced = replaced;
		CFG_UNREF(old_cfg);
	}

}
Example #5
0
static void *
reload_thread(void *unused)
{
	extern int yynerrs;
	extern FILE *yyin;
	FILE *f;
	struct config_file *new_cfg = NULL, *tmp;
	struct sigaction signals;

	/* Initialize signals and start reload thread */
	bzero (&signals, sizeof(struct sigaction));
	sigemptyset(&signals.sa_mask);
	sigaddset(&signals.sa_mask, SIGUSR1);
	signals.sa_handler = sig_usr1_handler;
	sigaction (SIGUSR1, &signals, NULL);

	msg_info("reload_thread: starting...");

	/* lock on mutex until we got SIGUSR1 that unlocks mutex */
	while (1) {
		pthread_mutex_lock (&cfg_reload_mtx);
		pthread_cond_wait (&cfg_cond, &cfg_reload_mtx);
		pthread_mutex_unlock (&cfg_reload_mtx);
		msg_warn("reload_thread: reloading, rmilter version %s", MVERSION);
		/* lock for writing */
		CFG_WLOCK()
		;
		f = fopen (cfg->cfg_name, "r");

		if (f == NULL) {
			CFG_UNLOCK()
			;
			msg_warn("reload_thread: cannot open file %s, %m", cfg->cfg_name);
			continue;
		}

		new_cfg = (struct config_file*) malloc (sizeof(struct config_file));
		if (new_cfg == NULL) {
			CFG_UNLOCK()
			;
			fclose (f);
			msg_warn("reload_thread: malloc, %s", strerror (errno));
			continue;
		}

		bzero (new_cfg, sizeof(struct config_file));
		init_defaults (new_cfg);
		new_cfg->cfg_name = cfg->cfg_name;
		tmp = cfg;
		cfg = new_cfg;

		yyin = f;
		yyrestart (yyin);

		if (yyparse () != 0 || yynerrs > 0) {
			CFG_UNLOCK()
			;
			fclose (f);
			msg_warn("reload_thread: cannot parse config file %s",
					cfg->cfg_name);
			free_config (new_cfg);
			free (new_cfg);
			cfg = tmp;
			continue;
		}

		fclose (f);
		new_cfg->cfg_name = tmp->cfg_name;
		new_cfg->serial = tmp->serial + 1;

		/* Strictly set temp dir */
		if (!cfg->temp_dir) {
			msg_warn("tempdir is not set, trying to use $TMPDIR");
			cfg->temp_dir = getenv ("TMPDIR");

			if (!cfg->temp_dir) {
				cfg->temp_dir = strdup ("/tmp");
			}
		}
#ifdef HAVE_SRANDOMDEV
		srandomdev();
#else
		srand (time (NULL));
#endif
		/* Free old config */
		free_config (tmp);
		free (tmp);

		CFG_UNLOCK()
		;
	}
	return NULL;
}