/* ** Modular Logfile Analyzer ** Copyright 2000 Jan Kneschke ** ** Homepage: http://www.modlogan.org ** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version, and provided that the above copyright and permission notice is included with all distributed copies of this or derived software. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ** ** $Id: mconfig.c,v 1.77 2004/08/27 18:32:51 ostborn Exp $ */ #define _GNU_SOURCE #include #include #include #include #include #include #include #ifdef HAVE_LIBADNS #include #endif #include "mlocale.h" #include "mconfig.h" #include "mdatatypes.h" #include "datatypes/count/datatype.h" #include "datatypes/string/datatype.h" #include "datatypes/match/datatype.h" #include "misc.h" #include "mplugins.h" static int linenumber = 0; static const char *filename = NULL; #define M_CONFIG_GROUP_UNKNOWN -1 #define M_CONFIG_GROUP_PARSE_ME 0 #define M_CONFIG_GROUP_DONT_PARSE_ME 1 FILE *mfopen (mconfig *ext_conf, const char *filename, const char *rights) { FILE *f = NULL; if (!(f = fopen (filename, rights))) { mlist *l; for (l = ext_conf->includepath; l && l->data; l = l->next) { char *fn; fn = malloc(strlen(l->data->key) + strlen(filename) + 2); sprintf(fn, "%s/%s", l->data->key, filename); if ((f = fopen (fn, "r")) != NULL) { free(fn); break; } free(fn); } } return f; } char *mconfig_get_value(mconfig *ext_conf, const char *value) { const char *d_pos; const char *s_pos; char *str; if (!value) return NULL; /* FIXME: a dumb guest */ str = malloc(1024); *str = '\0'; for (s_pos = value; (d_pos = strchr(s_pos, '$')); s_pos = d_pos) { const char *name_end; char *var_name; mdata *data; /* copy everything up to the '$' */ strncat(str, s_pos, d_pos-s_pos); /* a escaped $ */ if (*(d_pos+1) == '$') { /* add one $ to the output */ strcat(str, "$"); /* skip both $ */ d_pos += 2; } else { /* get the variable-name -> ([a-z_]+) */ d_pos++; for (name_end = d_pos; *name_end && (isalpha(*name_end) || *name_end == '_'); name_end++); /* extract variable-name */ var_name = malloc(name_end - d_pos + 1); strncpy(var_name, d_pos, name_end - d_pos); var_name[name_end - d_pos] = '\0'; /* get the value */ if ((data = mhash_get_data(ext_conf->variables, var_name))) { /* fprintf(stderr, "%s - found -> %s\n", var_name, data->data.brokenlink.referrer); */ strcat(str, data->data.string.string); } else { fprintf(stderr, "%s.%d: tried the insert the variable '%s', but it has never been registered by calling 'var(%s, ...)\n", __FILE__, __LINE__, var_name, var_name); } free(var_name); d_pos = name_end; } } strcat(str, s_pos); return str; } int mconfig_insert_value(mconfig *ext_conf, void *dest, int type, const char *value, int value_def) { pcre *match = NULL; const char *errptr; int erroffset = 0; #define N 20 + 1 int ovector[3 * N], n; const char **list; switch(type) { case M_CONFIG_TYPE_STRING: { char *str = *(char **)(dest); switch(value_def) { case M_CONFIG_VALUE_IGNORE: { if (str) break; str = strdup(value); assert(str); *(char **)(dest) = str; break; } case M_CONFIG_VALUE_APPEND: fprintf(stderr,"%s.%d: append not supported for string type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_OVERWRITE: if (str) free(str); str = strdup(value); assert(str); *(char **)(dest) = str; break; default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); return -1; } break; } case M_CONFIG_TYPE_STRING_LIST: { switch(value_def) { case M_CONFIG_VALUE_IGNORE: fprintf(stderr,"%s.%d: ignore not supported for grouping type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_APPEND: { mdata *data; mlist *l = *(mlist **)(dest); char *key = splaytree_insert(ext_conf->strings, value); data = mdata_Count_create(key, 1, M_DATA_STATE_PLAIN); mlist_insert(l, data); break; } case M_CONFIG_VALUE_OVERWRITE: fprintf(stderr,"%s.%d: overwrite not supported for grouping type\n", __FILE__, __LINE__); return -1; default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); return -1; } break; } case M_CONFIG_TYPE_COLTRIPPL: { char *str = *(char **)(dest); if (!is_htmltripple(value)) { fprintf(stderr, "%s.%d: %s (%s:%i): %s\n", __FILE__, __LINE__, _("Invalid colortripple"), filename, linenumber, value); return -1; } switch(value_def) { case M_CONFIG_VALUE_IGNORE: if (str) break; str = strdup(value); assert(str); *(char **)(dest) = str; break; case M_CONFIG_VALUE_APPEND: fprintf(stderr,"%s.%d: append not supported for colortripple type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_OVERWRITE: { char *_d; int j; if (str) free(str); str = malloc(strlen(value)+1); assert(str); j = 0; _d = str; while (value[j]) { *_d++ = toupper(value[j++]); } *_d = '\0'; *(char **)(dest) = str; break; } default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); return -1; } break; } case M_CONFIG_TYPE_SUBSTITUTE: { if ((match = pcre_compile( "^\"(.+)\"\\s*,\\s*(.+)$", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } if ((n = pcre_exec(match, NULL, value, strlen(value), 0, 0, ovector, 3 * N)) < 0) { if (n == PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: string doesn't match: %s\n", __FILE__, __LINE__, value); fprintf(stderr, "%s (%s:%i): %s\n", "grouping", filename, linenumber, value); } else { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); } free(match); return -1; } pcre_get_substring_list(value, ovector, n, &list); switch(value_def) { case M_CONFIG_VALUE_IGNORE: fprintf(stderr,"%s.%d: ignore not supported for grouping type\n", __FILE__, __LINE__); free(list); free(match); return -1; case M_CONFIG_VALUE_APPEND: { mdata *data; mlist *l = *(mlist **)(dest); char *key = splaytree_insert(ext_conf->strings, list[2]); if (NULL == (data = mdata_Match_create((char *)list[1], key))) { return -1; } mlist_append(l, data); #if 0 fprintf(stderr, "%p: %s\n", data, value); #endif break; } case M_CONFIG_VALUE_OVERWRITE: fprintf(stderr,"%s.%d: overwrite not supported for grouping type\n", __FILE__, __LINE__); free(list); free(match); return -1; default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); free(list); free(match); return -1; } pcre_free_substring_list(list); free(match); break; } case M_CONFIG_TYPE_MATCH: { if ((match = pcre_compile( "^\"(.+)\"$", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } if ((n = pcre_exec(match, NULL, value, strlen(value), 0, 0, ovector, 3 * N)) < 0) { if (n == PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: string doesn't match '\"\"': %s\n", __FILE__, __LINE__, value); fprintf(stderr, "%s (%s:%i): %s\n", "hiding", filename, linenumber, value); } else { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); } free(match); return -1; } pcre_get_substring_list(value, ovector, n, &list); switch(value_def) { case M_CONFIG_VALUE_IGNORE: fprintf(stderr,"%s.%d: ignore not supported for hiding type\n", __FILE__, __LINE__); free(list); free(match); return -1; case M_CONFIG_VALUE_APPEND: { mdata *data; mlist *l = *(mlist **)(dest); char *key; key = splaytree_insert(ext_conf->strings, ""); assert(key); data = mdata_Match_create(list[1], key); mlist_append(l, data); break; } case M_CONFIG_VALUE_OVERWRITE: fprintf(stderr,"%s.%d: overwrite not supported for hiding type\n", __FILE__, __LINE__); free(list); free(match); return -1; default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); free(list); free(match); return -1; } pcre_free_substring_list(list); free(match); break; } case M_CONFIG_TYPE_INT: { int str = *(int *)(dest); char *endp; switch(value_def) { case M_CONFIG_VALUE_IGNORE: fprintf(stderr,"%s.%d: ignore not supported for int type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_APPEND: fprintf(stderr,"%s.%d: append not supported for int type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_OVERWRITE: { str = strtol(value, &endp, 10); if (*endp != '\0') { fprintf(stderr, "%s (%s:%i): %s\n", _("Value isn't an integer in line"), filename, linenumber, value); return -1; } else { *(int *)(dest) = str; } break; } default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); return -1; } break; } case M_CONFIG_TYPE_CHAR: { char str = *(char *)(dest); switch(value_def) { case M_CONFIG_VALUE_IGNORE: fprintf(stderr,"%s.%d: ignore not supported for int type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_APPEND: fprintf(stderr,"%s.%d: append not supported for int type\n", __FILE__, __LINE__); return -1; case M_CONFIG_VALUE_OVERWRITE: { str = *value; *(char *)(dest) = str; break; } default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); return -1; } break; } default: fprintf(stderr,"%s.%d: unknown type of key-value definition\n", __FILE__, __LINE__); return -1; } #undef N return 0; } int mconfig_set_defaults(mconfig *conf) { if (conf == NULL) return -1; if (conf->statedir == NULL) { fprintf(stderr, "ERROR: [%s] no statefile-directory was set ( statedir = ... )\n", "global"); return -1; } if (dir_check_perms(conf->statedir)) { return -1; } #ifdef HAVE_LIBADNS conf->adns = (adns_state *)malloc(sizeof(adns_state)); assert(conf->adns); if (adns_init(conf->adns, 0, 0)) { fprintf(stderr, "%s.%d: Can't init the resolver\n", __FILE__, __LINE__); return -1; } #else if (conf->enable_resolver) { fprintf(stderr, "%s.%d: !! WARNING: You have enabled the resolver, but modlogan isn't compiled with resolver-support\n", __FILE__, __LINE__); } #endif /* read-ahead * * in combination with the resolver a value of 100 seems to be good: * http://jan.kneschke.de/projects/modlogan/docs/resolver.php * * increasing it might be a good idea * * if the resolver is disabled it should be as low as possible */ if (conf->read_ahead_limit == 0) { conf->read_ahead_limit = conf->enable_resolver ? 100 : 1; } if (mplugins_setup(conf)) { return -1; } /* loadplugins */ if (mplugins_load_plugins(conf)) { return -1; } return 0; } const char *mconfig_get_name_of_type(int type) { switch(type) { case M_CONFIG_TYPE_STRING: return "string"; case M_CONFIG_TYPE_STRING_LIST: return "string-list"; case M_CONFIG_TYPE_COLTRIPPL: return "color triple"; case M_CONFIG_TYPE_SUBSTITUTE: return "substitution"; case M_CONFIG_TYPE_MATCH: return "match"; case M_CONFIG_TYPE_INT: return "integer"; case M_CONFIG_TYPE_CHAR: return "character"; default: fprintf(stderr,"%s.%d: unknown type of key-value definition\n", __FILE__, __LINE__); return NULL; } } const char *mconfig_get_name_of_option(int option) { switch(option) { case M_CONFIG_VALUE_IGNORE: return "ignore"; case M_CONFIG_VALUE_APPEND: return "append"; case M_CONFIG_VALUE_OVERWRITE: return "overwrite"; default: fprintf(stderr,"%s.%d: unknown type of value definition\n", __FILE__, __LINE__); return NULL; } } int mconfig_show_options (const char *section, const mconfig_values config_values[]) { int i; fprintf(stderr, "\n,- section [%s] ->\n|\n", section); for (i = 0; config_values[i].string; i++) { fprintf(stderr, "| '%-20s' -> %-20s (%s)\n", config_values[i].string, mconfig_get_name_of_type(config_values[i].type), mconfig_get_name_of_option(config_values[i].value_def) ); } fprintf(stderr, "|\n`- section [%s] ->\n", section); return 0; } int mconfig_handle_cmdlineopts(mconfig *conf, const char *section, const mconfig_values config_values[]) { mlist *l; for (l = conf->cmdlineoptions; l && l->data; l = l->next) { /*
:= */ char *k, *v, *s; int i; s = l->data->key; if (NULL == (k = strchr(s, ':'))) continue; if (NULL == (v = strchr(k, '='))) continue; s = strndup(s, k - s); k = strndup(k + 1, v - k - 1); v = strdup(v + 1); if (0 != strcmp(s, section)) { free(s);free(k);free(v); continue; } for (i = 0; config_values[i].string; i++) { if (!strcmp(config_values[i].string, k)) break; } if (config_values[i].string) { if (mconfig_insert_value(conf, config_values[i].dest, config_values[i].type, v, config_values[i].value_def) != 0) { /* failed */ fprintf(stderr, "%s.%d: (%s:%d) parsing value of key '%s' failed (type = %d, value = %s)\n", __FILE__, __LINE__, filename, linenumber, config_values[i].string, config_values[i].type, v); free(s);free(k);free(v); return -1; } } else if (strcmp(k, "include") == 0){ /* unhandled */ fprintf(stderr, "%s.%d: -o %s: include is not possible\n", __FILE__, __LINE__, l->data->key); } else { fprintf(stderr, "%s.%d: -o %s: Unknown keyword '%s' in section [%s]\n", __FILE__, __LINE__, l->data->key, k, s); free(s);free(k);free(v); return -1; } free(s);free(k);free(v); } return 0; } int mconfig_parse_section(mconfig *conf, const char *cf, const char *section, const mconfig_values config_values[]) { FILE *f; int current_group = M_CONFIG_GROUP_DONT_PARSE_ME; char buf[255]; int locale_is_not_setup_yet = 1; int ln = 0; const char *old_fn; int base_level; int ret = 0; const char *errptr; int erroffset = 0; pcre * match_comment, *match_group, *match_keyvalue, *match_include, *match_variable; enum { M_CONFIG_LINE_UNSET, M_CONFIG_LINE_GROUP, M_CONFIG_LINE_COMMENT, M_CONFIG_LINE_KEYVALUE, M_CONFIG_LINE_VARIABLE }; base_level = (cf == NULL) || (cf == conf->configfile); old_fn = filename; filename = cf ? cf : conf->configfile; match_comment = match_group = match_keyvalue = match_include = match_variable = NULL; if (conf->show_options) { mconfig_show_options(section, config_values); } if (filename == NULL) { fprintf(stderr,"%s.%d: No configfilename specified\n", __FILE__, __LINE__); return -1; } if (!(f = mfopen(conf, filename, "r"))) { fprintf(stderr,"%s.%d: %s %s: %s\n", __FILE__, __LINE__, _("Can't open configfile"), filename, strerror(errno)); filename = old_fn; return -1; } if ((match_comment = pcre_compile( "^\\s*#", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } if ((match_group = pcre_compile( "^\\[(.+)\\]\\s*$", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } if ((match_keyvalue = pcre_compile( "^\\s*(.+?)\\s*=\\s*(.+)\\s*$", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } if ((match_variable = pcre_compile( "^\\s*var\\(\\s*(.+)\\s*,\\s*(.+)\\s*\\)\\s*$", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } if ((match_include = pcre_compile( "^(.+)\\s*,\\s*(.+)\\s*$", 0, &errptr, &erroffset, NULL)) == NULL) { fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } #ifdef DEBUG fprintf(stderr, "%s.%d: (config) %s - starting\n", __FILE__, __LINE__, filename); #endif while (fgets(buf, sizeof(buf)-1, f)) { #define N 20 + 1 int ovector[3 * N], n = 0, i; int type = M_CONFIG_LINE_UNSET; int buf_len = strlen(buf); if (feof(f)) { /* end of file */ break; } else if (buf_len == 0) { fprintf(stderr, "%s.%d: BUF_LEN == 0 -> DIE\n", __FILE__, __LINE__); return -1; } else if (buf[buf_len-1] != '\n' ) { fprintf(stderr, "%s.%d: (%s:%i) %s %d %s %s\n", __FILE__, __LINE__, filename, ln + 1, "Line longer than", sizeof(buf)-1,"characters - please fix it:", buf); filename = old_fn; return -1; } ln++; linenumber = ln; /* Strip superfluous spaces, tabs, \r, \n at end of line */ while (buf_len && buf[buf_len - 1] <= ' ') { buf[buf_len - 1] = '\n'; buf[buf_len] = '\0'; buf_len--; } if (buf_len <= 1) continue; if (type == M_CONFIG_LINE_UNSET) { if ((n = pcre_exec(match_group, NULL, buf, buf_len, 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); filename = old_fn; return -1; } } else { type = M_CONFIG_LINE_GROUP; } } if (type == M_CONFIG_LINE_UNSET) { if ((n = pcre_exec(match_comment, NULL, buf, buf_len, 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); filename = old_fn; return -1; } } else { type = M_CONFIG_LINE_COMMENT; } } if (type == M_CONFIG_LINE_UNSET) { if ((n = pcre_exec(match_keyvalue, NULL, buf, buf_len, 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); filename = old_fn; return -1; } } else { type = M_CONFIG_LINE_KEYVALUE; } } if (type == M_CONFIG_LINE_UNSET) { if ((n = pcre_exec(match_variable, NULL, buf, buf_len, 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); filename = old_fn; return -1; } } else { type = M_CONFIG_LINE_VARIABLE; } } switch(type) { case M_CONFIG_LINE_GROUP: { const char **list; int parsed_section_finished = current_group; pcre_get_substring_list(buf, ovector, n, &list); current_group = (strcmp(list[1], section) == 0) ? M_CONFIG_GROUP_PARSE_ME : M_CONFIG_GROUP_DONT_PARSE_ME; if (parsed_section_finished == M_CONFIG_GROUP_PARSE_ME && current_group == M_CONFIG_GROUP_DONT_PARSE_ME && base_level == 1) { /* handle the command line options */ if (mconfig_handle_cmdlineopts(conf, section, config_values)) return -1; } if (locale_is_not_setup_yet) { init_locale(conf); locale_is_not_setup_yet = 0; } free(list); break; } case M_CONFIG_LINE_COMMENT: break; case M_CONFIG_LINE_VARIABLE: { const char *key, *value; const char **list; mdata *data; if (current_group != M_CONFIG_GROUP_PARSE_ME) break; pcre_get_substring_list(buf, ovector, n, &list); value = list[2]; key = list[1]; if (*value != '$' || (*value == '$' && *(value+1) == '$')) { /* a plain string */ char *dkey = splaytree_insert(conf->strings, key); data = mdata_String_create(dkey, value); } else { /* a variable */ int j; for (j = 0; config_values[j].string; j++) { if (!strcmp(config_values[j].string, value+1)) break; } if (config_values[j].string) { if (config_values[j].type == M_CONFIG_TYPE_STRING) { if (*(char **)config_values[j].dest != NULL) { char *dkey = splaytree_insert(conf->strings, key); data = mdata_String_create(dkey, *(char **)config_values[j].dest); } else { fprintf(stderr, "ERROR: var(%s, %s) failed because %s is empty\n", key, value, value+1); return -1; } } else { fprintf(stderr, "ERROR: var(%s, %s) failed because %s isn't a string-variable\n", key, value, value+1); return -1; } } else { fprintf(stderr, "ERROR: var(%s, %s) failed because %s isn't a valid config-variable\n", key, value, value+1); return -1; } } mhash_insert_sorted(conf->variables, data); free(list); break; } case M_CONFIG_LINE_KEYVALUE: { const char *key, *value; const char **list; if (current_group != M_CONFIG_GROUP_PARSE_ME) break; pcre_get_substring_list(buf, ovector, n, &list); value = list[2]; key = list[1]; i = 0; if (conf->debug_level > 3) fprintf(stderr, "%s.%d: <%s> [%s] %s - %s\n", __FILE__, __LINE__, filename, section, key, value); /* while (config_values[i].string) { fprintf(stderr, "%s.%d: '%s', %d, %d, %p\n", __FILE__, __LINE__, config_values[i].string, config_values[i].type, config_values[i].value_def, config_values[i].dest); i++; }*/ for (i = 0; config_values[i].string; i++) { if (!strcmp(config_values[i].string, key)) break; } if (config_values[i].string) { if (mconfig_insert_value(conf, config_values[i].dest, config_values[i].type, value, config_values[i].value_def) != 0) { /* failed */ fprintf(stderr, "%s.%d: (%s:%d) parsing value of key '%s' failed (type = %d, value = %s)\n", __FILE__, __LINE__, filename, linenumber, config_values[i].string, config_values[i].type, value); return -1; } } else if (strcmp(key, "include") == 0){ if ((n = pcre_exec(match_include, NULL, value, strlen(value), 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); filename = old_fn; return -1; } } if (n == 3) { const char **inc_list; pcre_get_substring_list(value, ovector, n, &inc_list); if (mconfig_parse_section(conf, inc_list[1], inc_list[2], config_values)) { fprintf(stderr, "%s.%d: parsing included configfile failed (%s)\n", __FILE__, __LINE__, inc_list[1]); fclose(f); pcre_free_substring_list(list); pcre_free_substring_list(inc_list); filename = old_fn; return -1; } free(inc_list); } else { fprintf(stderr, "%s.%d: include -- not matched like it should: %d\n", __FILE__, __LINE__, n); filename = old_fn; return -1; } } else { fprintf(stderr, "%s.%d: Unknown keyword '%s' in section [%s] (%s:%i): %s\n", __FILE__, __LINE__, key, section, filename, linenumber, buf); filename = old_fn; return -1; } free(list); break; } default: fprintf(stderr, "%s.%d: (section [%s] (%s:%i)) parse error: '%s'\n", __FILE__, __LINE__, section, filename, linenumber, buf); filename = old_fn; return -1; } } if (current_group == M_CONFIG_GROUP_PARSE_ME && base_level == 1) { /* handle the command-line options */ if (mconfig_handle_cmdlineopts(conf, section, config_values)) return -1; } fclose (f); pcre_free(match_comment); pcre_free(match_group); pcre_free(match_keyvalue); pcre_free(match_include); pcre_free(match_variable); #ifdef DEBUG fprintf(stderr, "%s.%d: (config) %s - done\n", __FILE__, __LINE__, filename); #endif filename = old_fn; return ret; } mconfig *mconfig_init() { mconfig *conf = malloc(sizeof(mconfig)); if (!conf) return NULL; memset(conf, 0, sizeof(mconfig)); conf->loadplugins = mlist_init(); conf->includepath = mlist_init(); conf->variables = mhash_init(4); conf->version = strdup(VERSION); assert(conf->version); #ifdef HAVE_LIBADNS conf->adns = NULL; conf->query_hash = mhash_init( 128 ); #endif conf->cmdlineoptions = mlist_init(); conf->strings = splaytree_init(); return conf; } int mconfig_read(mconfig *conf, const char *cf) { const mconfig_values config_values[] = { /* strings */ {"loadplugin", M_CONFIG_TYPE_STRING_LIST, M_CONFIG_VALUE_APPEND, &(conf->loadplugins)}, {"includepath", M_CONFIG_TYPE_STRING_LIST, M_CONFIG_VALUE_APPEND, &(conf->includepath)}, {"statedir", M_CONFIG_TYPE_STRING, M_CONFIG_VALUE_OVERWRITE, &(conf->statedir)}, /* integers */ {"incremental", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->incremental)}, {"debug_level", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->debug_level)}, {"gen_report_threshold",M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->gen_report_threshold)}, {"enable_resolver", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->enable_resolver)}, {"debug_resolver", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->debug_resolver)}, {"compress_mode", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->compress_mode)}, {"show_available_config_options", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->show_options)}, {"read_ahead_limit", M_CONFIG_TYPE_INT, M_CONFIG_VALUE_OVERWRITE, &(conf->read_ahead_limit)}, {NULL, M_CONFIG_TYPE_INT, 0, NULL} }; #ifdef PKGSYSCONFDIR const char *def_cf_dir = PKGSYSCONFDIR; #else const char *def_cf_dir = "./"; #endif const char *def_cf_name = "modlogan.conf"; if (!conf) return -1; if (!cf) { conf->configfile = malloc(strlen(def_cf_dir) + strlen(def_cf_name) + 2); assert(conf->configfile); strcpy(conf->configfile, def_cf_dir); strcat(conf->configfile, "/"); strcat(conf->configfile, def_cf_name); } else { conf->configfile = strdup(cf); assert(conf->configfile); } /* read the 'global' section from the configfile */ if (mconfig_parse_section(conf, conf->configfile, "global", config_values)) return -1; if (conf->show_options) { mconfig_show_options("global", config_values); } if (mconfig_set_defaults(conf) != 0) return -1; return 0; } int mconfig_free(mconfig *conf) { if (!conf) return -1; mplugins_free(conf); if (conf->statedir) free(conf->statedir); #ifdef HAVE_LIBADNS if (conf->adns) { adns_finish(*(conf->adns)); free(conf->adns); } if (conf->query_hash) mhash_free(conf->query_hash); #endif mlist_free(conf->loadplugins); mlist_free(conf->includepath); mlist_free(conf->cmdlineoptions); mhash_free(conf->variables); free(conf->configfile); free(conf->version); free(conf); return 0; }