/*-
* Copyright (c) 2005 Andrey Simonenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#ifndef lint
static const char rcsid[] ATTR_UNUSED =
"@(#)$Id: ipastat_rules.c,v 1.1.4.2 2007/05/11 16:29:59 simon Exp $";
#endif /* !lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/queue.h>
#include "ipa_mod.h"
#include "dlapi.h"
#include "confcommon.h"
#include "memfunc.h"
#include "parser.h"
#include "ipastat_log.h"
#include "ipastat_conf.h"
#include "ipastat_main.h"
#include "ipastat_rules.h"
#include "ipastat_st.h"
#ifndef RULES_HASH_BUCKETS
# define RULES_HASH_BUCKETS 128 /* Must be power of 2. */
#endif
int dynamic_rules = -1; /* dynamic_rules parameter. */
struct opt_rule *cur_opt_rule = NULL; /* Current optional rule. */
ipa_mzone *rule_mzone; /* Mzone for all struct rule{}. */
ipa_mzone *rulepat_mzone; /* Mzone for all struct rulepat{}. */
struct rules_list rules_list =
STAILQ_HEAD_INITIALIZER(rules_list); /* List of all rules. */
struct rulepats_list rulepats_list =
STAILQ_HEAD_INITIALIZER(rulepats_list); /* List of rulepats. */
u_int nrules = 0; /* Number of rules. */
struct opt_rules_list opt_rules_list = STAILQ_HEAD_INITIALIZER(opt_rules_list);
SLIST_HEAD(rules_hash, rule);
static struct rules_hash rules_hash[RULES_HASH_BUCKETS];
/*
* Init one rule.
*/
static int
init_rule(const struct opt_rule *opt_rule)
{
struct rule *rule;
rule = opt_rule->rule;
if (!rule->inited) {
rule->inited = 1;
/* Init in modules. */
if (st_init_rule(rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: init_rule: st_init_rule failed",
rule->rule_name);
return -1;
}
}
return 0;
}
/*
* Init rules and limits or thresholds.
*/
int
init_rules(void)
{
const struct opt_rule *opt_rule;
STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
if (init_rule(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "init_rules: init_rule failed");
return -1;
}
#ifdef WITH_LIMITS
if (has_opt_limits)
if (init_limits(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "init_rules: init_limits failed");
return -1;
}
#endif
#ifdef WITH_THRESHOLDS
if (has_opt_thresholds)
if (init_thresholds(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "init_rules: init_thresholds failed");
return -1;
}
#endif
}
return 0;
}
/*
* Release memory used by one rule.
*/
static void
free_rule(struct rule *rule)
{
#ifdef WITH_LIMITS
free_limits(&rule->limits);
#endif
#ifdef WITH_THRESHOLDS
free_thresholds(&rule->thresholds);
#endif
if (rule->free_mask & RULE_FREE_NAME)
mem_free(rule->rule_name, m_anon);
mem_free(rule->rule_info, m_result);
mzone_free(rule_mzone, rule);
}
/*
* Call free_rule() for each rule.
*/
void
free_rules(void)
{
struct rule *rule, *rule_next;
for (rule = STAILQ_FIRST(&rules_list); rule != NULL; rule = rule_next) {
rule_next = STAILQ_NEXT(rule, list);
free_rule(rule);
}
STAILQ_INIT(&rules_list);
}
/*
* Deinit one rule.
*/
static int
deinit_rule(const struct opt_rule *opt_rule)
{
int error = 0;
struct rule *rule;
rule = opt_rule->rule;
if (rule->inited) {
rule->inited = 0;
/* Deinit in modules. */
if (st_deinit_rule(rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: deinit_rule: st_deinit_rule failed",
rule->rule_name);
error = -1;
}
}
return error;
}
/*
* Deinit previously inited rules, limits or thresholds.
*/
int
deinit_rules(void)
{
int error = 0;
struct opt_rule *opt_rule;
STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
if (deinit_rule(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "deinit_rules: deinit_rule failed");
error = -1;
}
#ifdef WITH_LIMITS
if (has_opt_limits)
if (deinit_limits(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "deinit_rules: deinit_limits failed");
error = -1;
}
#endif
#ifdef WITH_THRESHOLDS
if (has_opt_thresholds)
if (deinit_thresholds(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "deinit_rules: deinit_thresholds failed");
error = -1;
}
#endif
}
return error;
}
/*
* Return hash_value for the given rule_name;
*/
static u_int
get_rule_hash_value(const char *rule_name)
{
u_int hash_value;
for (hash_value = 0; *rule_name != '\0'; ++rule_name)
hash_value += (u_char)*rule_name;
return hash_value;
}
#define get_rules_bucket(x) ((x) & (RULES_HASH_BUCKETS - 1))
/*
* Add rule to rules_hash.
*/
void
add_rule_to_hash(struct rule *rule)
{
rule->hash_value = get_rule_hash_value(rule->rule_name);
SLIST_INSERT_HEAD(&rules_hash[get_rules_bucket(rule->hash_value)], rule, hlink);
}
void
init_rules_hash(void)
{
struct rules_hash *hash;
for (hash = rules_hash; hash < rules_hash + RULES_HASH_BUCKETS; ++hash)
SLIST_INIT(hash);
}
/*
* Return pointer to rule with the given name.
*/
struct rule *
rule_by_name(const char *rule_name)
{
u_int hash_value;
struct rule *rule;
const struct rules_hash *hash;
hash_value = get_rule_hash_value(rule_name);
hash = &rules_hash[get_rules_bucket(hash_value)];
SLIST_FOREACH(rule, hash, hlink)
if (rule->hash_value == hash_value &&
strcmp(rule->rule_name, rule_name) == 0)
return rule;
return NULL;
}
struct rule *
alloc_rule(void)
{
struct rule *rule;
if ( (rule = mzone_alloc(rule_mzone)) == NULL) {
xlogmsgx(IPA_LOG_ERR, "alloc_rule: mzone_alloc failed");
return NULL;
}
rule->rule_info = NULL;
rule->ruleno = nrules++;
rule->st_list = NULL;
#ifdef WITH_LIMITS
STAILQ_INIT(&rule->limits);
#endif
#ifdef WITH_THRESHOLDS
STAILQ_INIT(&rule->thresholds);
#endif
rule->inited = 0;
STAILQ_INSERT_TAIL(&rules_list, rule, list);
return rule;
}
/*
* Add one optional rule given in the -q -r option.
*/
int
add_opt_rule(const char *rule_name)
{
struct opt_rule *opt_rule;
if ( (opt_rule = mem_malloc(sizeof *opt_rule, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "add_opt_rule: mem_malloc failed");
return -1;
}
opt_rule->rule_name = rule_name;
opt_rule->opt_st = cur_opt_st;
opt_rule->type = OPT_RULE_RULE;
opt_rule->data = NULL;
#ifdef WITH_LIMITS
STAILQ_INIT(&opt_rule->opt_limits);
#endif
#ifdef WITH_THRESHOLDS
STAILQ_INIT(&opt_rule->opt_thresholds);
#endif
STAILQ_INSERT_TAIL(&opt_rules_list, opt_rule, link);
cur_opt_rule = opt_rule;
return 0;
}
/*
* Parse all rules, limits and thresholds names given in the
* command line.
*/
int
parse_opt_rules(void)
{
struct rule *rule;
struct opt_rule *opt_rule;
const struct rulepat *rulepat;
STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
if ( (rule = rule_by_name(opt_rule->rule_name)) == NULL) {
/* This rule is not given in configuration file. */
if (!dynamic_rules) {
logmsgx(IPA_LOG_ERR, "parse_opt_rules: unknown rule %s",
opt_rule->rule_name);
return -1;
}
if ( (rule = alloc_rule()) == NULL) {
logmsgx(IPA_LOG_ERR, "parse_opt_rules: alloc_rule failed");
return -1;
}
rule->rule_name = (char *)opt_rule->rule_name;
rule->free_mask = 0;
add_rule_to_hash(rule);
}
if (opt_rule->opt_st != NULL)
rule->st_list = opt_rule->opt_st->st_list;
STAILQ_FOREACH(rulepat, &rulepats_list, link)
if (regexec(&rulepat->reg, rule->rule_name, 0, (regmatch_t *)NULL, 0) == 0) {
/* Inherit some settings for rule{} from rulepat{}. */
if (rule->st_list == NULL)
rule->st_list = rulepat->st_list;
#ifdef WITH_LIMITS
if (STAILQ_EMPTY(&rule->limits) && !STAILQ_EMPTY(&rulepat->limits))
if (copy_limits(rule, &rulepat->limits) < 0) {
logmsgx(IPA_LOG_ERR, "parse_opt_rules: rule %s: cannot copy all limits from rulepat %s",
rule->rule_name, parser_buf_to_string(rulepat->pat));
return -1;
}
#endif
#ifdef WITH_THRESHOLDS
if (STAILQ_EMPTY(&rule->thresholds) && !STAILQ_EMPTY(&rulepat->thresholds))
if (copy_thresholds(rule, &rulepat->thresholds) < 0) {
logmsgx(IPA_LOG_ERR, "parse_opt_rule: rule %s: cannot copy all thresholds from rulepat %s",
rule->rule_name, parser_buf_to_string(rulepat->pat));
return -1;
}
#endif
if (mod_conf_inherit(rulepat, rule) < 0) {
logmsgx(IPA_LOG_ERR, "parse_opt_rules: mod_conf_inherit failed");
return -1;
}
if (rulepat->check_next_rulepat == 0)
break;
}
if (rulepat == NULL) {
/* Inherit some settings for rule{} from global{}. */
if (rule->st_list == NULL)
rule->st_list = global_st_list;
}
opt_rule->rule = rule;
#ifdef WITH_LIMITS
if (parse_opt_limits(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "parse_opt_rules: parse_opt_limits failed");
return -1;
}
#endif
#ifdef WITH_THRESHOLDS
if (parse_opt_thresholds(opt_rule) < 0) {
logmsgx(IPA_LOG_ERR, "parse_opt_rules: parse_opt_thresholds failed");
return -1;
}
#endif
}
return 0;
}
/*
* Release memory used by all opt_rule structures.
*/
void
free_opt_rules(void)
{
struct opt_rule *opt_rule, *opt_rule_next;
for (opt_rule = STAILQ_FIRST(&opt_rules_list); opt_rule != NULL; opt_rule = opt_rule_next) {
opt_rule_next = STAILQ_NEXT(opt_rule, link);
#ifdef WITH_LIMITS
free_opt_limits(&opt_rule->opt_limits);
#endif
#ifdef WITH_THRESHOLDS
free_opt_thresholds(&opt_rule->opt_thresholds);
#endif
mem_free(opt_rule, m_anon);
}
}
/*
* Release memory used by all rulepats.
*/
void
free_rulepats(void)
{
struct rulepat *rulepat;
STAILQ_FOREACH(rulepat, &rulepats_list, link) {
mem_free(rulepat->pat, m_parser);
regfree(&rulepat->reg);
#ifdef WITH_LIMITS
free_limits(&rulepat->limits);
#endif
#ifdef WITH_THRESHOLDS
free_thresholds(&rulepat->thresholds);
#endif
}
mzone_deinit(rulepat_mzone);
}
syntax highlighted by Code2HTML, v. 0.9.1