* pfw/system.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include "internal.h"
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
* Private Functions
****************************************************************************/
static void pfw_free_plugins(pfw_system_t* system)
{
pfw_plugin_t* plugin;
int i;
for (i = 0; (plugin = pfw_vector_get(system->plugins, i)); i++) {
free(plugin->parameter);
free(plugin->name);
free(plugin);
}
pfw_vector_free(system->plugins);
}
* @brief Convert ammends to string.
*/
static void pfw_apply_ammends(pfw_vector_t* ammends, char* res, int len)
{
pfw_criterion_t* criterion;
pfw_ammend_t* ammend;
int pos = 0, ret, i;
for (i = 0; (ammend = pfw_vector_get(ammends, i)); i++) {
criterion = ammend->u.criterion;
if (ammend->type == PFW_AMMEND_RAW) {
ret = snprintf(res + pos, len - pos, "%s", ammend->u.raw);
} else if (ammend->u.criterion->type == PFW_CRITERION_NUMERICAL) {
ret = snprintf(res + pos, len - pos, "%" PRId32, criterion->state);
} else {
ret = pfw_criterion_itoa(criterion, criterion->state,
res + pos, len - pos);
}
if (ret < 0)
return;
pos += ret;
if (pos >= len)
return;
}
}
* @brief Check wether apply needed, and update 'current' field.
*/
static bool pfw_apply_need(pfw_domain_t* domain, pfw_config_t* config)
{
char buffer[PFW_MAXLEN_AMMENDS];
bool apply = false;
if (domain->current != config) {
domain->current = config;
apply = true;
}
pfw_apply_ammends(config->name, buffer, sizeof(buffer));
if (apply || !config->current || strcmp(config->current, buffer)) {
free(config->current);
config->current = strdup(buffer);
return true;
}
return false;
}
* @brief Apply paramter to plugin callback.
*/
static void pfw_apply_acts(pfw_vector_t* action)
{
char buffer[PFW_MAXLEN_AMMENDS];
pfw_act_t* act;
int i;
for (i = 0; (act = pfw_vector_get(action, i)); i++) {
pfw_apply_ammends(act->param, buffer, sizeof(buffer));
act->plugin.p->cb(act->plugin.p->cookie, buffer);
free(act->plugin.p->parameter);
act->plugin.p->parameter = strdup(buffer);
}
}
* Public Functions
****************************************************************************/
* @brief Apply criteria changes to domains.
*/
void pfw_apply(void* handle)
{
pfw_system_t* system = handle;
pfw_domain_t* domain;
pfw_config_t* config;
int i, j;
if (!system)
return;
pthread_mutex_lock(&system->mutex);
for (i = 0; (domain = pfw_vector_get(system->domains, i)); i++) {
for (j = 0; (config = pfw_vector_get(domain->configs, j)); j++) {
if (pfw_rule_match(config->rules)) {
if (pfw_apply_need(domain, config)) {
syslog(LOG_INFO, "pfw domain:%s switch to conf:%s\n", domain->name, config->current);
pfw_apply_acts(config->acts);
}
break;
}
}
}
pthread_mutex_unlock(&system->mutex);
}
static void* pfw_plugin_register(pfw_system_t* system, const pfw_plugin_def_t* def)
{
pfw_plugin_t* plugin;
int ret = -ENOMEM;
if (!def || !def->name)
return NULL;
plugin = malloc(sizeof(pfw_plugin_t));
if (!plugin)
return NULL;
plugin->parameter = NULL;
plugin->cookie = def->cookie;
plugin->cb = def->cb;
plugin->name = strdup(def->name);
if (!plugin->name)
goto err1;
ret = pfw_vector_append(&system->plugins, plugin);
if (ret < 0)
goto err2;
return plugin;
err2:
free(plugin->name);
err1:
free(plugin);
return NULL;
}
void* pfw_create(const char* criteria, const char* settings,
const pfw_plugin_def_t* defs, int nb, pfw_load_t on_load,
pfw_save_t on_save, void* cookie)
{
pfw_system_t* system;
int i;
system = calloc(1, sizeof(pfw_system_t));
if (!system)
return NULL;
pthread_mutex_init(&system->mutex, NULL);
system->on_load = on_load;
system->on_save = on_save;
system->cookie = cookie;
for (i = 0; i < nb; i++) {
if (!pfw_plugin_register(system, &defs[i]))
goto err;
}
system->criteria_ctx = pfw_context_create(criteria);
if (!system->criteria_ctx)
goto err;
if (pfw_parse_criteria(system->criteria_ctx, &system->criteria) < 0)
goto err;
if (!pfw_sanitize_criteria(system))
goto err;
system->settings_ctx = pfw_context_create(settings);
if (!system->settings_ctx)
goto err;
if (pfw_parse_settings(system->settings_ctx, &system->domains) < 0)
goto err;
if (!pfw_sanitize_settings(system))
goto err;
return system;
err:
return NULL;
}
void pfw_destroy(void* handle, pfw_release_t on_release)
{
pfw_system_t* system = handle;
if (system) {
if (on_release)
on_release(system->cookie);
pfw_context_destroy(system->criteria_ctx);
pfw_context_destroy(system->settings_ctx);
pfw_free_criteria(system->criteria);
pfw_free_settings(system->domains);
pfw_free_plugins(system);
pthread_mutex_destroy(&system->mutex);
free(system);
}
}