Cleanup of configuration internals. Use an n-ary type tree for everything instead of a first level hash branching off into n-ary type trees.

Reduces the code and uses a uniform internal data structure.
remotes/origin/master-1.0.x
Jason Ish 16 years ago committed by Victor Julien
parent 38dc7ffebc
commit ea277a0b36

@ -17,19 +17,6 @@
#define YAML_VERSION_MAJOR 1 #define YAML_VERSION_MAJOR 1
#define YAML_VERSION_MINOR 1 #define YAML_VERSION_MINOR 1
/* Define to print the current YAML state. */
#undef PRINT_STATES
#ifdef PRINT_STATES
#define DPRINT_STATE(x) do { SCLogDebug x ; } while (0)
#else
#define DPRINT_STATE(x)
#endif /* PRINT_STATES */
/* Defines the maximum number of levels YAML may nest. This is
* primarily used for construction of lookup-keys for configuration
* values. */
#define MAX_LEVELS 16
/* Sometimes we'll have to create a node name on the fly (integer /* Sometimes we'll have to create a node name on the fly (integer
* conversion, etc), so this is a default length to allocate that will * conversion, etc), so this is a default length to allocate that will
* work most of the time. */ * work most of the time. */
@ -39,57 +26,18 @@
enum conf_state { enum conf_state {
CONF_KEY = 0, CONF_KEY = 0,
CONF_VAL, CONF_VAL,
CONF_SEQ,
}; };
/**
* \brief Return the name of the current configuration key value.
*
* This function returns the current value of the configuration key.
* This is all the key components joined together with a ".".
*
* NOTE: This function is not re-entrant safe, but we do not expect to
* be loading configuration files concurrently.
*/
static char *
GetKeyName(char **key, int level)
{
/* Statically allocate a string that should be large enough. */
static char print_key[1024];
int i;
print_key[0] = '\0';
for (i = 0; i <= level; i++) {
if (key[i] == NULL)
break;
if (strlen(key[i]) + strlen(print_key) + 2 > sizeof(print_key)) {
/* Overflow. */
return NULL;
}
else {
strlcat(print_key, key[i], sizeof(print_key));
if (i < level)
strlcat(print_key, ".", sizeof(print_key));
}
}
return print_key;
}
/** /**
* \brief Parse a YAML layer. * \brief Parse a YAML layer.
* *
* This will eventually replace ConfYamlParse but for now its just
* used to load lists.
*
* \param parser A pointer to an active yaml_parser_t. * \param parser A pointer to an active yaml_parser_t.
* \param parent The parent configuration node. * \param parent The parent configuration node.
* *
* \retval 0 on success, -1 on failure. * \retval 0 on success, -1 on failure.
*/ */
static int static int
ConfYamlParse2(yaml_parser_t *parser, ConfNode *parent, int inseq) ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq)
{ {
ConfNode *node = parent; ConfNode *node = parent;
yaml_event_t event; yaml_event_t event;
@ -104,7 +52,26 @@ ConfYamlParse2(yaml_parser_t *parser, ConfNode *parent, int inseq)
return -1; return -1;
} }
if (event.type == YAML_SCALAR_EVENT) { if (event.type == YAML_DOCUMENT_START_EVENT) {
/* Verify YAML version - its more likely to be a valid
* Suricata configuration file if the version is
* correct. */
yaml_version_directive_t *ver =
event.data.document_start.version_directive;
if (ver == NULL) {
fprintf(stderr, "ERROR: Invalid configuration file.\n\n");
fprintf(stderr, "The configuration file must begin with the following two lines:\n\n");
fprintf(stderr, "%%YAML 1.1\n---\n\n");
goto fail;
}
int major = event.data.document_start.version_directive->major;
int minor = event.data.document_start.version_directive->minor;
if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) {
fprintf(stderr, "ERROR: Invalid YAML version. Must be 1.1\n");
goto fail;
}
}
else if (event.type == YAML_SCALAR_EVENT) {
char *value = (char *)event.data.scalar.value; char *value = (char *)event.data.scalar.value;
SCLogDebug("event.type = YAML_SCALAR_EVENT (%s) inseq=%d\n", SCLogDebug("event.type = YAML_SCALAR_EVENT (%s) inseq=%d\n",
value, inseq); value, inseq);
@ -117,6 +84,20 @@ ConfYamlParse2(yaml_parser_t *parser, ConfNode *parent, int inseq)
} }
else { else {
if (state == CONF_KEY) { if (state == CONF_KEY) {
/* If the node already exists, check if we can
* override it. If we can, free it then continue
* otherwise move onto the next configuration
* parameter. */
ConfNode *n0 = ConfNodeLookupChild(parent, value);
if (n0 != NULL) {
if (n0->allow_override) {
ConfNodeRemove(n0);
}
else {
state = CONF_VAL;
goto next;
}
}
if (parent->is_seq) { if (parent->is_seq) {
if (parent->val == NULL) { if (parent->val == NULL) {
parent->val = strdup(value); parent->val = strdup(value);
@ -135,7 +116,7 @@ ConfYamlParse2(yaml_parser_t *parser, ConfNode *parent, int inseq)
} }
else if (event.type == YAML_SEQUENCE_START_EVENT) { else if (event.type == YAML_SEQUENCE_START_EVENT) {
SCLogDebug("event.type = YAML_SEQUENCE_START_EVENT\n"); SCLogDebug("event.type = YAML_SEQUENCE_START_EVENT\n");
if (ConfYamlParse2(parser, node, 1) != 0) if (ConfYamlParse(parser, node, 1) != 0)
goto fail; goto fail;
state = CONF_KEY; state = CONF_KEY;
} }
@ -151,10 +132,10 @@ ConfYamlParse2(yaml_parser_t *parser, ConfNode *parent, int inseq)
seq_node->name = calloc(1, DEFAULT_NAME_LEN); seq_node->name = calloc(1, DEFAULT_NAME_LEN);
snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++); snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++);
TAILQ_INSERT_TAIL(&node->head, seq_node, next); TAILQ_INSERT_TAIL(&node->head, seq_node, next);
ConfYamlParse2(parser, seq_node, 0); ConfYamlParse(parser, seq_node, 0);
} }
else { else {
ConfYamlParse2(parser, node, inseq); ConfYamlParse(parser, node, inseq);
} }
state = CONF_KEY; state = CONF_KEY;
} }
@ -166,130 +147,7 @@ ConfYamlParse2(yaml_parser_t *parser, ConfNode *parent, int inseq)
done = 1; done = 1;
} }
yaml_event_delete(&event); next:
continue;
fail:
yaml_event_delete(&event);
return -1;
}
return 0;
}
/**
* \brief Process a YAML parser.
*
* Loads a configuration from a setup YAML parser.
*
* \param parser A YAML parser setup for processing.
*/
static int
ConfYamlParse(yaml_parser_t *parser)
{
yaml_event_t event;
int done;
int level;
int state;
int inseq;
char *key[MAX_LEVELS];
memset(key, 0, sizeof(key));
state = CONF_KEY;
done = 0;
level = -1;
inseq = 0;
while (!done) {
if (!yaml_parser_parse(parser, &event)) {
fprintf(stderr, "Failed to parse configuration file: %s\n",
parser->problem);
return -1;
}
switch (event.type) {
case YAML_STREAM_START_EVENT:
break;
case YAML_STREAM_END_EVENT:
done = 1;
break;
case YAML_DOCUMENT_START_EVENT: {
/* Verify YAML version - its more likely to be a valid
* Suricata configuration file if the version is
* correct. */
yaml_version_directive_t *ver =
event.data.document_start.version_directive;
if (ver == NULL) {
fprintf(stderr, "ERROR: Invalid configuration file.\n\n");
fprintf(stderr, "The configuration file must begin with the following two lines:\n\n");
fprintf(stderr, "%%YAML 1.1\n---\n\n");
goto fail;
}
int major = event.data.document_start.version_directive->major;
int minor = event.data.document_start.version_directive->minor;
if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) {
fprintf(stderr, "ERROR: Invalid YAML version. Must be 1.1\n");
goto fail;
}
break;
}
case YAML_DOCUMENT_END_EVENT:
/* Ignored. */
break;
case YAML_SEQUENCE_START_EVENT: {
ConfNode *new;
new = ConfNodeNew();
new->name = strdup(GetKeyName(key, level));
ConfYamlParse2(parser, new, 1);
ConfSetNode(new);
state = CONF_KEY;
break;
}
case YAML_SEQUENCE_END_EVENT:
break;
case YAML_MAPPING_START_EVENT:
level++;
if (level == MAX_LEVELS) {
fprintf(stderr,
"Reached maximum configuration nesting level.\n");
goto fail;
}
/* Since we are entering a new mapping, state goes back to key. */
state = CONF_KEY;
break;
case YAML_MAPPING_END_EVENT:
if (level > -1) {
free(key[level]);
key[level] = NULL;
}
level--;
break;
case YAML_SCALAR_EVENT: {
char *value = (char *)event.data.scalar.value;
if (level < 0) {
/* Don't process values until we've hit a mapping. */
continue;
}
if (state == CONF_KEY) {
if (key[level] != NULL)
free(key[level]);
key[level] = strdup(value);
/* Move state to expecting a value. */
state = CONF_VAL;
}
else if (state == CONF_VAL) {
ConfSet(GetKeyName(key, level), value, 1);
state = CONF_KEY;
}
break;
}
case YAML_ALIAS_EVENT:
break;
case YAML_NO_EVENT:
break;
}
yaml_event_delete(&event); yaml_event_delete(&event);
continue; continue;
@ -319,6 +177,7 @@ ConfYamlLoadFile(const char *filename)
FILE *infile; FILE *infile;
yaml_parser_t parser; yaml_parser_t parser;
int ret; int ret;
ConfNode *root = ConfGetRootNode();
if (yaml_parser_initialize(&parser) != 1) { if (yaml_parser_initialize(&parser) != 1) {
fprintf(stderr, "Failed to initialize yaml parser.\n"); fprintf(stderr, "Failed to initialize yaml parser.\n");
@ -333,7 +192,7 @@ ConfYamlLoadFile(const char *filename)
return -1; return -1;
} }
yaml_parser_set_input_file(&parser, infile); yaml_parser_set_input_file(&parser, infile);
ret = ConfYamlParse(&parser); ret = ConfYamlParse(&parser, root, 0);
yaml_parser_delete(&parser); yaml_parser_delete(&parser);
fclose(infile); fclose(infile);
@ -346,15 +205,16 @@ ConfYamlLoadFile(const char *filename)
int int
ConfYamlLoadString(const char *string, size_t len) ConfYamlLoadString(const char *string, size_t len)
{ {
ConfNode *root = ConfGetRootNode();
yaml_parser_t parser; yaml_parser_t parser;
int ret; int ret;
if (yaml_parser_initialize(&parser) != 1) { if (yaml_parser_initialize(&parser) != 1) {
fprintf(stderr, "Failed to initialize yaml parser.\n"); fprintf(stderr, "Failed to initialize yaml parser.\n");
return -1; exit(EXIT_FAILURE);
} }
yaml_parser_set_input_string(&parser, (const unsigned char *)string, len); yaml_parser_set_input_string(&parser, (const unsigned char *)string, len);
ret = ConfYamlParse(&parser); ret = ConfYamlParse(&parser, root, 0);
yaml_parser_delete(&parser); yaml_parser_delete(&parser);
return ret; return ret;
@ -378,8 +238,9 @@ default-log-dir: /tmp\n\
ConfCreateContextBackup(); ConfCreateContextBackup();
ConfInit(); ConfInit();
ConfNode *node;
ConfYamlLoadString(input, strlen(input)); ConfYamlLoadString(input, strlen(input));
ConfNode *node;
node = ConfGetNode("rule-files"); node = ConfGetNode("rule-files");
if (node == NULL) if (node == NULL)
return 0; return 0;
@ -555,7 +416,8 @@ libhtp:\n\
ConfCreateContextBackup(); ConfCreateContextBackup();
ConfInit(); ConfInit();
ConfYamlLoadString(input, strlen(input)); if (ConfYamlLoadString(input, strlen(input)) != 0)
return 0;
ConfNode *outputs; ConfNode *outputs;
outputs = ConfGetNode("libhtp.server-config"); outputs = ConfGetNode("libhtp.server-config");

@ -11,86 +11,20 @@
* *
* \author Endace Technology Limited - Jason Ish <jason.ish@endace.com> * \author Endace Technology Limited - Jason Ish <jason.ish@endace.com>
* *
* \todo Consider using HashListTable to allow easy dumping of all data. * \todo Consider having the in-memory configuration database a direct
* reflection of the configuration file and moving command line
* parameters to a primary lookup table?
*/ */
#include <string.h>
#include "suricata-common.h" #include "suricata-common.h"
#include "conf.h" #include "conf.h"
#include "util-hash.h"
#include "util-unittest.h" #include "util-unittest.h"
#include "util-debug.h" #include "util-debug.h"
#define CONF_HASH_TBL_SIZE 1024 static ConfNode *root = NULL;
static ConfNode *root_backup = NULL;
static HashTable *conf_hash = NULL;
/* temporary variable that would be used to hold the hash_table instance
* present in conf_hash. Used while running tests that require their
* own yaml conf file. The backup can be set and then be reused by using
* the function ConfCreateContextBackup() and ConfRestoreContextBackup() */
static HashTable *backup_conf_hash = NULL;
/**
* \brief Function to generate the hash of a configuration value.
*
* This is a callback function provided to HashTable for creating the
* hash key. Its a simple wrapper around the generic hash function
* the passes on the configuration parameter name.
*
* \retval The hash ID of the configuration parameters name.
*/
static uint32_t
ConfHashFunc(HashTable *ht, void *data, uint16_t len)
{
ConfNode *cn = (ConfNode *)data;
uint32_t hash;
hash = HashTableGenericHash(ht, cn->name, strlen(cn->name));
SCLogDebug("%s -> %" PRIu32 "", cn->name, hash);
return hash;
}
/**
* \brief Function to compare 2 hash nodes.
*
* This is a callback function provided to the HashTable for comparing
* 2 nodes.
*
* \retval 1 if equivalant otherwise 0.
*/
static char
ConfHashComp(void *a, uint16_t a_len, void *b, uint16_t b_len)
{
ConfNode *ca = (ConfNode *)a;
ConfNode *cb = (ConfNode *)b;
if (strcmp(ca->name, cb->name) == 0)
return 1;
else
return 0;
}
/**
* \brief Callback function to free a hash node.
*/
static void ConfHashFree(void *data)
{
ConfNode *cn = (ConfNode *)data;
if (cn == NULL)
return;
/** \todo VJ apparently the list that is free is also in the hash
* individually resulting in double free errors if we
* call ConfNodeFree (that clears the list) from this
* hash free function */
if (cn->name != NULL)
free(cn->name);
if (cn->val != NULL)
free(cn->val);
free(cn);
//ConfNodeFree(cn);
}
/** /**
* \brief Initialize the configuration system. * \brief Initialize the configuration system.
@ -98,18 +32,16 @@ static void ConfHashFree(void *data)
void void
ConfInit(void) ConfInit(void)
{ {
/* Prevent double initialization. */ if (root != NULL) {
if (conf_hash != NULL) {
SCLogDebug("already initialized"); SCLogDebug("already initialized");
return; return;
} }
root = ConfNodeNew();
conf_hash = HashTableInit(CONF_HASH_TBL_SIZE, ConfHashFunc, ConfHashComp, if (root == NULL) {
ConfHashFree); SCLogError(SC_ERR_MEM_ALLOC,
if (conf_hash == NULL) { "ERROR: Failed to allocate memory for root configuration node, "
fprintf(stderr, "aborting.");
"ERROR: Failed to allocate memory for configuration, aborting.\n"); exit(EXIT_FAILURE);
exit(1);
} }
SCLogDebug("configuration module initialized"); SCLogDebug("configuration module initialized");
} }
@ -158,50 +90,43 @@ ConfNodeFree(ConfNode *node)
} }
/** /**
* \brief Set a configuration node. * \brief Get a ConfNode by name.
*
* \param key The full name of the configuration node to lookup.
* *
* \retval 1 on success, 0 on failure. * \retval A pointer to ConfNode is found or NULL if the configuration
* node does not exist.
*/ */
int ConfNode *
ConfSetNode(ConfNode *node) ConfGetNode(char *key)
{ {
ConfNode lookup; ConfNode *node = root;
ConfNode *pnode; char *saveptr;
char *token;
lookup.name = node->name; /* Need to dup the key for tokenization... */
pnode = HashTableLookup(conf_hash, &lookup, sizeof(lookup)); char *tokstr = strdup(key);
if (pnode != NULL) {
if (!pnode->allow_override) {
return 0;
}
HashTableRemove(conf_hash, pnode, sizeof(*pnode));
}
if (HashTableAdd(conf_hash, node, sizeof(*node)) != 0) { token = strtok_r(tokstr, ".", &saveptr);
SCLogError(SC_ERR_MEM_ALLOC, "Failed to add new configuration node."); for (;;) {
exit(EXIT_FAILURE); node = ConfNodeLookupChild(node, token);
if (node == NULL)
break;
token = strtok_r(NULL, ".", &saveptr);
if (token == NULL)
break;
} }
free(tokstr);
return 1; return node;
} }
/** /**
* \brief Get a ConfNode by key. * \brief Get the root configuration node.
*
* \param key The lookup key of the node to find.
*
* \retval The node matching the key or NULL if not found.
*/ */
ConfNode * ConfNode *
ConfGetNode(char *key) ConfGetRootNode(void)
{ {
ConfNode lookup; return root;
ConfNode *node;
lookup.name = key;
node = HashTableLookup(conf_hash, &lookup, sizeof(lookup));
return node;
} }
/** /**
@ -216,37 +141,65 @@ ConfGetNode(char *key)
int int
ConfSet(char *name, char *val, int allow_override) ConfSet(char *name, char *val, int allow_override)
{ {
ConfNode lookup_key, *conf_node; ConfNode *parent = root;
ConfNode *node;
char *token;
char *saveptr;
lookup_key.name = name; /* First check if the node already exists. */
conf_node = HashTableLookup(conf_hash, &lookup_key, sizeof(lookup_key)); node = ConfGetNode(name);
if (conf_node != NULL) { if (node != NULL) {
if (!conf_node->allow_override) { if (!node->allow_override) {
return 0; return 0;
} }
HashTableRemove(conf_hash, conf_node, sizeof(*conf_node)); else {
} if (node->val != NULL)
free(node->val);
conf_node = ConfNodeNew(); node->val = strdup(val);
if (conf_node == NULL) { node->allow_override = allow_override;
return 0; return 1;
}
} }
conf_node->name = strdup(name); else {
conf_node->val = strdup(val); char *tokstr = strdup(name);
conf_node->allow_override = allow_override; token = strtok_r(tokstr, ".", &saveptr);
node = ConfNodeLookupChild(parent, token);
if (HashTableAdd(conf_hash, conf_node, sizeof(*conf_node)) != 0) { for (;;) {
fprintf(stderr, "ERROR: Failed to set configuration parameter %s\n", if (node == NULL) {
name); node = ConfNodeNew();
exit(1); node->name = strdup(token);
node->parent = parent;
TAILQ_INSERT_TAIL(&parent->head, node, next);
parent = node;
}
token = strtok_r(NULL, ".", &saveptr);
if (token == NULL) {
if (node->val != NULL)
free(node->val);
node->val = strdup(val);
node->allow_override = allow_override;
break;
}
else {
node = ConfNodeLookupChild(parent, token);
}
}
free(tokstr);
} }
SCLogDebug("configuration parameter '%s' set", name); SCLogDebug("configuration parameter '%s' set", name);
return 1; return 1;
} }
/** /**
* \brief Retrieve a configuration value. * \brief Retrieve the value of a configuration node.
*
* This function will return the value for a configuration node based
* on the full name of the node. It is possible that the value
* returned could be NULL, this could happen if the requested node
* does exist but is not a node that contains a value, but contains
* children ConfNodes instead.
* *
* \param name Name of configuration parameter to get. * \param name Name of configuration parameter to get.
* \param vptr Pointer that will be set to the configuration value parameter. * \param vptr Pointer that will be set to the configuration value parameter.
@ -258,21 +211,13 @@ ConfSet(char *name, char *val, int allow_override)
int int
ConfGet(char *name, char **vptr) ConfGet(char *name, char **vptr)
{ {
ConfNode lookup_key; ConfNode *node = ConfGetNode(name);
ConfNode *conf_node; if (node == NULL) {
if (conf_hash == NULL)
return 0;
lookup_key.name = name;
conf_node = HashTableLookup(conf_hash, &lookup_key, sizeof(lookup_key));
if (conf_node == NULL) {
SCLogDebug("failed to lookup configuration parameter '%s'", name); SCLogDebug("failed to lookup configuration parameter '%s'", name);
return 0; return 0;
} }
else { else {
*vptr = conf_node->val; *vptr = node->val;
return 1; return 1;
} }
} }
@ -339,6 +284,17 @@ ConfGetBool(char *name, int *val)
return 1; return 1;
} }
/**
* \brief Remove (and free) the provided configuration node.
*/
void
ConfNodeRemove(ConfNode *node)
{
if (node->parent != NULL)
TAILQ_REMOVE(&node->parent->head, node, next);
ConfNodeFree(node);
}
/** /**
* \brief Remove a configuration parameter from the configuration db. * \brief Remove a configuration parameter from the configuration db.
* *
@ -350,13 +306,15 @@ ConfGetBool(char *name, int *val)
int int
ConfRemove(char *name) ConfRemove(char *name)
{ {
ConfNode cn; ConfNode *node;
cn.name = name; node = ConfGetNode(name);
if (HashTableRemove(conf_hash, &cn, sizeof(cn)) == 0) if (node == NULL)
return 1;
else
return 0; return 0;
else {
ConfNodeRemove(node);
return 1;
}
} }
/** /**
@ -365,8 +323,8 @@ ConfRemove(char *name)
void void
ConfCreateContextBackup(void) ConfCreateContextBackup(void)
{ {
backup_conf_hash = conf_hash; root_backup = root;
conf_hash = NULL; root = NULL;
return; return;
} }
@ -378,7 +336,7 @@ ConfCreateContextBackup(void)
void void
ConfRestoreContextBackup(void) ConfRestoreContextBackup(void)
{ {
conf_hash = backup_conf_hash; root = root_backup;
return; return;
} }
@ -389,11 +347,8 @@ ConfRestoreContextBackup(void)
void void
ConfDeInit(void) ConfDeInit(void)
{ {
if (conf_hash == NULL) if (root != NULL)
return; ConfNodeFree(root);
HashTableFree(conf_hash);
conf_hash = NULL;
SCLogDebug("configuration module de-initialized"); SCLogDebug("configuration module de-initialized");
} }
@ -428,16 +383,14 @@ ConfNodeDump(ConfNode *node, const char *prefix)
level++; level++;
TAILQ_FOREACH(child, &node->head, next) { TAILQ_FOREACH(child, &node->head, next) {
name[level] = strdup(child->name); name[level] = strdup(child->name);
// if (child->val != NULL) { if (prefix == NULL) {
if (prefix == NULL) { printf("%s = %s\n", ConfPrintNameArray(name, level),
printf("%s = %s\n", ConfPrintNameArray(name, level), child->val);
child->val); }
} else {
else { printf("%s.%s = %s\n", prefix,
printf("%s.%s = %s\n", prefix, ConfPrintNameArray(name, level), child->val);
ConfPrintNameArray(name, level), child->val); }
}
//}
ConfNodeDump(child, prefix); ConfNodeDump(child, prefix);
free(name[level]); free(name[level]);
} }
@ -450,22 +403,7 @@ ConfNodeDump(ConfNode *node, const char *prefix)
void void
ConfDump(void) ConfDump(void)
{ {
HashTableBucket *b; ConfNodeDump(root, NULL);
ConfNode *cn;
uint32_t u;
for (u = 0; u < conf_hash->array_size; u++) {
if (conf_hash->array[u] != NULL) {
b = (HashTableBucket *)conf_hash->array[u];
while (b != NULL) {
cn = (ConfNode *)b->data;
if (cn->val != NULL)
printf("%s = %s\n", cn->name, cn->val);
ConfNodeDump(cn, cn->name);
b = b->next;
}
}
}
} }
/** /**
@ -553,38 +491,6 @@ ConfTestSetAndGet(void)
return 1; return 1;
} }
static int
ConfTestSetGetNode(void)
{
ConfNode *set;
ConfNode *get;
char key[] = "some-key";
char val[] = "some-val";
set = ConfNodeNew();
if (set == NULL)
return 0;
set->name = strdup(key);
set->val = strdup(val);
if (ConfSetNode(set) != 1)
return 0;
get = ConfGetNode(key);
if (get == NULL)
return 0;
if (strcmp(get->name, key) != 0)
return 0;
if (strcmp(get->val, val) != 0)
return 0;
ConfRemove(key);
get = ConfGetNode(key);
if (get != NULL)
return 0;
return 1;
}
/** /**
* Test that overriding a value is allowed provided allow_override is * Test that overriding a value is allowed provided allow_override is
* true and that the config parameter gets the new value. * true and that the config parameter gets the new value.
@ -647,13 +553,14 @@ ConfTestOverrideValue2(void)
static int static int
ConfTestGetInt(void) ConfTestGetInt(void)
{ {
char name[] = "some-int"; char name[] = "some-int.x";
intmax_t val; intmax_t val;
if (ConfSet(name, "0", 1) != 1) if (ConfSet(name, "0", 1) != 1)
return 0; return 0;
if (ConfGetInt(name, &val) != 1) if (ConfGetInt(name, &val) != 1)
return 0; return 0;
return 1;
if (val != 0) if (val != 0)
return 0; return 0;
@ -816,11 +723,37 @@ ConfNodeLookupChildValueTest(void)
return 1; return 1;
} }
/**
* Test the removal of a configuration node.
*/
static int
ConfNodeRemoveTest(void)
{
ConfCreateContextBackup();
ConfInit();
if (ConfSet("some.nested.parameter", "blah", 1) != 1)
return 0;
ConfNode *node = ConfGetNode("some.nested.parameter");
if (node == NULL)
return 0;
ConfNodeRemove(node);
node = ConfGetNode("some.nested.parameter");
if (node != NULL)
return 0;
ConfDeInit();
ConfRestoreContextBackup();
return 1;
}
void void
ConfRegisterTests(void) ConfRegisterTests(void)
{ {
UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1);
UtRegisterTest("ConfTestSetGetNode", ConfTestSetGetNode, 1);
UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet, 1); UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet, 1);
UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1, 1); UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1, 1);
UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2, 1); UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2, 1);
@ -828,6 +761,7 @@ ConfRegisterTests(void)
UtRegisterTest("ConfTestGetBool", ConfTestGetBool, 1); UtRegisterTest("ConfTestGetBool", ConfTestGetBool, 1);
UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest, 1); UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest, 1);
UtRegisterTest("ConfNodeLookupChildValueTest", ConfNodeLookupChildValueTest, 1); UtRegisterTest("ConfNodeLookupChildValueTest", ConfNodeLookupChildValueTest, 1);
UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest, 1);
} }
#endif /* UNITTESTS */ #endif /* UNITTESTS */

@ -19,6 +19,7 @@ typedef struct ConfNode_ {
int is_seq; int is_seq;
int allow_override; int allow_override;
struct ConfNode_ *parent;
TAILQ_HEAD(, ConfNode_) head; TAILQ_HEAD(, ConfNode_) head;
TAILQ_ENTRY(ConfNode_) next; TAILQ_ENTRY(ConfNode_) next;
} ConfNode; } ConfNode;
@ -30,6 +31,8 @@ typedef struct ConfNode_ {
#define DEFAULT_LOG_DIR "/var/log/suricata" #define DEFAULT_LOG_DIR "/var/log/suricata"
void ConfInit(void); void ConfInit(void);
void ConfDeInit(void);
ConfNode *ConfGetRootNode(void);
int ConfGet(char *name, char **vptr); int ConfGet(char *name, char **vptr);
int ConfGetInt(char *name, intmax_t *val); int ConfGetInt(char *name, intmax_t *val);
int ConfGetBool(char *name, int *val); int ConfGetBool(char *name, int *val);
@ -38,13 +41,12 @@ void ConfDump(void);
void ConfNodeDump(ConfNode *node, const char *prefix); void ConfNodeDump(ConfNode *node, const char *prefix);
ConfNode *ConfNodeNew(void); ConfNode *ConfNodeNew(void);
void ConfNodeFree(ConfNode *); void ConfNodeFree(ConfNode *);
int ConfSetNode(ConfNode *node);
ConfNode *ConfGetNode(char *key); ConfNode *ConfGetNode(char *key);
void ConfCreateContextBackup(void); void ConfCreateContextBackup(void);
void ConfRestoreContextBackup(void); void ConfRestoreContextBackup(void);
void ConfDeInit(void);
ConfNode *ConfNodeLookupChild(ConfNode *node, const char *key); ConfNode *ConfNodeLookupChild(ConfNode *node, const char *key);
const char *ConfNodeLookupChildValue(ConfNode *node, const char *key); const char *ConfNodeLookupChildValue(ConfNode *node, const char *key);
void ConfNodeRemove(ConfNode *);
void ConfRegisterTests(); void ConfRegisterTests();
#endif /* ! __CONF_H__ */ #endif /* ! __CONF_H__ */

Loading…
Cancel
Save