diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2010-04-01 19:45:35 +0400 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2010-04-01 19:45:35 +0400 |
commit | 6be82def714f297d54302953286223b4afb07208 (patch) | |
tree | b156eea2e245efeb95702cc6bae6beaa02341440 | |
parent | a43a37453f497a919fb4a5358615d89f18706935 (diff) | |
download | rspamd-6be82def714f297d54302953286223b4afb07208.tar.gz rspamd-6be82def714f297d54302953286223b4afb07208.zip |
* Add dumper to XML file (not all sections yet)
* Add checksum to config files
* Some config parsing reorganizations:
- post_load_config should be called after xml initialization
- xml state machine is corrected to read main section variables
- some linting is added to xml (checking of elements parity)
-rw-r--r-- | src/cfg_file.h | 22 | ||||
-rw-r--r-- | src/cfg_file.l | 1 | ||||
-rw-r--r-- | src/cfg_utils.c | 36 | ||||
-rw-r--r-- | src/cfg_xml.c | 279 | ||||
-rw-r--r-- | src/cfg_xml.h | 11 | ||||
-rw-r--r-- | src/main.c | 6 |
6 files changed, 310 insertions, 45 deletions
diff --git a/src/cfg_file.h b/src/cfg_file.h index b4f5a0e1f..3ec7391e4 100644 --- a/src/cfg_file.h +++ b/src/cfg_file.h @@ -266,16 +266,18 @@ struct config_file { GHashTable* factors; /**< hash of factors indexed by symbol name */ GHashTable* c_modules; /**< hash of c modules indexed by module name */ GHashTable* composite_symbols; /**< hash of composite symbols indexed by its name */ - GList *classifiers; /**< list of all classifiers defined */ - GList *statfiles; /**< list of all statfiles in config file order */ - GHashTable *classifiers_symbols; /**< hashtable indexed by symbol name of classifiers */ - GHashTable* cfg_params; /**< all cfg params indexed by its name in this structure */ + GList *classifiers; /**< list of all classifiers defined */ + GList *statfiles; /**< list of all statfiles in config file order */ + GHashTable *classifiers_symbols; /**< hashtable indexed by symbol name of classifiers */ + GHashTable* cfg_params; /**< all cfg params indexed by its name in this structure */ int clock_res; /**< resolution of clock used */ double grow_factor; /**< grow factor for consolidation callback */ GList *views; /**< views */ - GHashTable* domain_settings; /**< settings per-domains */ - GHashTable* user_settings; /**< settings per-user */ - + GHashTable* domain_settings; /**< settings per-domains */ + GHashTable* user_settings; /**< settings per-user */ + + gchar* checksum; /**< real checksum of config file */ + gchar* dump_checksum; /**< dump checksum of config file */ }; /** @@ -361,6 +363,12 @@ gchar* substitute_variable (struct config_file *cfg, gchar *name, gchar *str, gu */ void post_load_config (struct config_file *cfg); +/** + * Calculate checksum for config file + * @param cfg config file + */ +gboolean get_config_checksum (struct config_file *cfg); + /** * Replace all \" with a single " in given string diff --git a/src/cfg_file.l b/src/cfg_file.l index fd83be66c..83c35290c 100644 --- a/src/cfg_file.l +++ b/src/cfg_file.l @@ -163,7 +163,6 @@ yes|YES|no|NO|[yY]|[nN] yylval.flag=parse_flag(yytext); return FLAG; if ( --include_stack_ptr < 0 ) { include_stack_ptr = 0; yylineno = 1; - post_load_config (cfg); yyterminate (); } else { diff --git a/src/cfg_utils.c b/src/cfg_utils.c index d2f75e11c..18677a1ca 100644 --- a/src/cfg_utils.c +++ b/src/cfg_utils.c @@ -230,6 +230,9 @@ free_config (struct config_file *cfg) g_hash_table_remove_all (cfg->cfg_params); g_hash_table_unref (cfg->cfg_params); g_hash_table_destroy (cfg->classifiers_symbols); + if (cfg->checksum) { + g_free (cfg->checksum); + } g_list_free (cfg->classifiers); g_list_free (cfg->metrics_list); memory_pool_delete (cfg->cfg_pool); @@ -499,6 +502,37 @@ fill_cfg_params (struct config_file *cfg) } +gboolean +get_config_checksum (struct config_file *cfg) +{ + int fd; + void *map; + struct stat st; + + /* Compute checksum for config file that should be used by xml dumper */ + if ((fd = open (cfg->cfg_name, O_RDONLY)) == -1) { + msg_err ("config file %s is no longer available, cannot calculate checksum"); + return FALSE; + } + if (stat (cfg->cfg_name, &st) == -1) { + msg_err ("cannot stat %s: %s", cfg->cfg_name, strerror (errno)); + return FALSE; + } + + /* Now mmap this file to simplify reading process */ + if ((map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + msg_err ("cannot mmap %s: %s", cfg->cfg_name, strerror (errno)); + close (fd); + return FALSE; + } + close (fd); + + /* Get checksum for a file */ + cfg->checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, map, st.st_size); + munmap (map, st.st_size); + + return TRUE; +} /* * Perform post load actions */ @@ -539,7 +573,7 @@ post_load_config (struct config_file *cfg) cfg->metrics_list = g_list_prepend (cfg->metrics_list, def_metric); g_hash_table_insert (cfg->metrics, DEFAULT_METRIC, def_metric); } - + } diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 93c8a5785..aa9ccf2fe 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -81,6 +81,24 @@ static struct xml_parser_rule grammar[] = { NULL }, { + "raw_mode", + xml_handle_boolean, + G_STRUCT_OFFSET (struct config_file, raw_mode), + NULL + }, + { + "tempdir", + xml_handle_string, + G_STRUCT_OFFSET (struct config_file, temp_dir), + NULL + }, + { + "checksum", + xml_handle_string, + G_STRUCT_OFFSET (struct config_file, dump_checksum), + NULL + }, + { "statfile_pool_size", xml_handle_size, G_STRUCT_OFFSET (struct config_file, max_statfile_size), @@ -718,7 +736,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam if (g_ascii_strcasecmp (element_name, "module") == 0) { /* Read module data */ if (extract_attr ("name", attribute_names, attribute_values, &res)) { - g_strlcpy (ud->section_name, res, sizeof (res)); + g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); ud->state = XML_READ_MODULE; } else { @@ -734,7 +752,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam } else if (g_ascii_strcasecmp (element_name, "metric") == 0) { if (extract_attr ("name", attribute_names, attribute_values, &res)) { - g_strlcpy (ud->section_name, res, sizeof (res)); + g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); ud->state = XML_READ_METRIC; /* Create object */ ud->other_data = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct metric)); @@ -746,7 +764,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam } else if (g_ascii_strcasecmp (element_name, "classifier") == 0) { if (extract_attr ("type", attribute_names, attribute_values, &res)) { - g_strlcpy (ud->section_name, res, sizeof (res)); + g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); ud->state = XML_READ_CLASSIFIER; /* Create object */ ud->other_data = check_classifier_cfg (ud->cfg, NULL); @@ -761,25 +779,21 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam /* Create object */ ud->other_data = check_worker_conf (ud->cfg, NULL); } - else { - /* Other params */ - if (g_ascii_strcasecmp (element_name, "variable") == 0) { - if (extract_attr ("name", attribute_names, attribute_values, &res)) { - g_strlcpy (ud->section_name, res, sizeof (res)); - ud->state = XML_READ_VARIABLE; - } - else { - *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'variable'"); - ud->state = XML_ERROR; - } - - } - else if (g_ascii_strcasecmp (element_name, "pidfile") == 0) { - ud->state = XML_READ_PIDFILE; + else if (g_ascii_strcasecmp (element_name, "variable") == 0) { + if (extract_attr ("name", attribute_names, attribute_values, &res)) { + g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); + ud->state = XML_READ_VARIABLE; } - else if (g_ascii_strcasecmp (element_name, "filters") == 0) { - ud->state = XML_READ_FILTERS; + else { + *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'variable'"); + ud->state = XML_ERROR; } + + } + else { + /* Extract other tags */ + g_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); + ud->state = XML_READ_VALUE; } break; case XML_READ_MODULE: @@ -857,14 +871,9 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, case XML_READ_VARIABLE: CHECK_TAG ("variable", TRUE); break; - case XML_READ_PIDFILE: - CHECK_TAG ("pidfile", TRUE); - break; - case XML_READ_STATFILE_POOL: - CHECK_TAG ("statfile_pool_size", TRUE); - break; - case XML_READ_FILTERS: - CHECK_TAG ("filters", TRUE); + case XML_READ_VALUE: + /* Check tags parity */ + CHECK_TAG (ud->section_name, TRUE); break; case XML_READ_LOGGING: CHECK_TAG ("logging", FALSE); @@ -930,9 +939,7 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len } break; case XML_READ_VARIABLE: - case XML_READ_PIDFILE: - case XML_READ_STATFILE_POOL: - case XML_READ_FILTERS: + case XML_READ_VALUE: if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_MAIN)) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); ud->state = XML_ERROR; @@ -944,8 +951,6 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len ud->state = XML_ERROR; } break; - case XML_READ_PARAM: - break; default: ud->state = XML_ERROR; break; @@ -961,3 +966,211 @@ rspamd_xml_error (GMarkupParseContext *context, GError *error, gpointer user_dat msg_err ("xml parser error: %s, at state %d", error->message, ud->state); } + +/* Dumper part */ + +/* Dump specific sections */ + +/* Dump main section variables */ +static gboolean +xml_dump_main (struct config_file *cfg, FILE *f) +{ + char *escaped_str; + + /* Print header comment */ + fprintf (f, "<!-- Main section -->" CRLF); + + escaped_str = g_markup_escape_text (cfg->temp_dir, -1); + fprintf (f, " <tempdir>%s</tempdir>" CRLF, escaped_str); + g_free (escaped_str); + + escaped_str = g_markup_escape_text (cfg->pid_file, -1); + fprintf (f, " <pidfile>%s</pidfile>" CRLF, escaped_str); + g_free (escaped_str); + + escaped_str = g_markup_escape_text (cfg->filters_str, -1); + fprintf (f, " <filters>%s</filters>" CRLF, escaped_str); + g_free (escaped_str); + + if (cfg->checksum) { + escaped_str = g_markup_escape_text (cfg->checksum, -1); + fprintf (f, " <checksum>%s</checksum>" CRLF, escaped_str); + g_free (escaped_str); + } + + fprintf (f, " <raw_mode>%s</raw_mode>" CRLF, cfg->raw_mode ? "yes" : "no"); + + /* Print footer comment */ + fprintf (f, "<!-- End of main section -->" CRLF); + + return TRUE; +} + +/* Dump variables section */ +static void +xml_variable_callback (gpointer key, gpointer value, gpointer user_data) +{ + FILE *f = user_data; + char *escaped_key, *escaped_value; + + escaped_key = g_markup_escape_text (key, -1); + escaped_value = g_markup_escape_text (value, -1); + fprintf (f, " <variable name=\"%s\">%s</variable>" CRLF, escaped_key, escaped_value); + g_free (escaped_key); + g_free (escaped_value); +} + +static gboolean +xml_dump_variables (struct config_file *cfg, FILE *f) +{ + /* Print header comment */ + fprintf (f, "<!-- Variables section -->" CRLF); + + /* Iterate through variables */ + g_hash_table_foreach (cfg->variables, xml_variable_callback, (gpointer)f); + + /* Print footer comment */ + fprintf (f, "<!-- End of variables section -->" CRLF); + + return TRUE; +} + +/* Workers */ +static void +xml_worker_param_callback (gpointer key, gpointer value, gpointer user_data) +{ + FILE *f = user_data; + char *escaped_key, *escaped_value; + + escaped_key = g_markup_escape_text (key, -1); + escaped_value = g_markup_escape_text (value, -1); + fprintf (f, " <param name=\"%s\">%s</param>" CRLF, escaped_key, escaped_value); + g_free (escaped_key); + g_free (escaped_value); +} + +static gboolean +xml_dump_workers (struct config_file *cfg, FILE *f) +{ + GList *cur; + struct worker_conf *wrk; + char *escaped_str; + + /* Print header comment */ + fprintf (f, "<!-- Workers section -->" CRLF); + + /* Iterate through list */ + cur = g_list_first (cfg->workers); + while (cur) { + wrk = cur->data; + + fprintf (f, "<worker>" CRLF); + switch (wrk->type) { + case TYPE_WORKER: + fprintf (f, " <type>normal</type>" CRLF); + break; + case TYPE_CONTROLLER: + fprintf (f, " <type>controller</type>" CRLF); + break; + case TYPE_FUZZY: + fprintf (f, " <type>fuzzy</type>" CRLF); + break; + case TYPE_LMTP: + fprintf (f, " <type>lmtp</type>" CRLF); + break; + } + escaped_str = g_markup_escape_text (wrk->bind_host, -1); + fprintf (f, " <bind_socket>%s</bind_socket>" CRLF, escaped_str); + g_free (escaped_str); + + fprintf (f, " <count>%u</count>" CRLF, wrk->count); + fprintf (f, " <maxfiles>%u</maxfiles>" CRLF, wrk->rlimit_nofile); + fprintf (f, " <maxcore>%u</maxcore>" CRLF, wrk->rlimit_maxcore); + + /* Now dump other attrs */ + fprintf (f, "<!-- Other params -->" CRLF); + g_hash_table_foreach (wrk->params, xml_worker_param_callback, f); + + fprintf (f, "</worker>" CRLF); + + cur = g_list_next (cur); + } + + /* Print footer comment */ + fprintf (f, "<!-- End of workers section -->" CRLF); + + return TRUE; +} + +/* Modules dump */ +static void +xml_module_callback (gpointer key, gpointer value, gpointer user_data) +{ + FILE *f = user_data; + char *escaped_key, *escaped_value; + GList *cur; + struct module_opt *opt; + + escaped_key = g_markup_escape_text (key, -1); + fprintf (f, "<!-- %s -->" CRLF, escaped_key); + fprintf (f, "<module name=\"%s\">" CRLF, escaped_key); + g_free (escaped_key); + + cur = g_list_first (value); + while (cur) { + opt = cur->data; + escaped_key = g_markup_escape_text (opt->param, -1); + escaped_value = g_markup_escape_text (opt->value, -1); + fprintf (f, " <option name=\"%s\">%s</option>" CRLF, escaped_key, escaped_value); + g_free (escaped_key); + g_free (escaped_value); + cur = g_list_next (cur); + } + fprintf (f, "</module>" CRLF); +} + +static gboolean +xml_dump_modules (struct config_file *cfg, FILE *f) +{ + /* Print header comment */ + fprintf (f, "<!-- Modules section -->" CRLF); + + /* Iterate through variables */ + g_hash_table_foreach (cfg->modules_opts, xml_module_callback, (gpointer)f); + + /* Print footer comment */ + fprintf (f, "<!-- End of modules section -->" CRLF); + + return TRUE; +} + +#define CHECK_RES do { if (!res) { fclose (f); return FALSE; } } while (0) +gboolean +xml_dump_config (struct config_file *cfg, const char *filename) +{ + FILE *f; + gboolean res = FALSE; + + f = fopen (filename, "w"); + if (f == NULL) { + msg_err ("cannot open file '%s': %s", filename, strerror (errno)); + return FALSE; + } + + /* Header */ + fprintf (f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" CRLF "<rspamd>" CRLF); + /* Now dump all parts of config */ + res = xml_dump_main (cfg, f); + CHECK_RES; + res = xml_dump_variables (cfg, f); + CHECK_RES; + res = xml_dump_workers (cfg, f); + CHECK_RES; + res = xml_dump_modules (cfg, f); + CHECK_RES; + /* Footer */ + fprintf (f, "</rspamd>" CRLF); + fclose (f); + + return TRUE; +} diff --git a/src/cfg_xml.h b/src/cfg_xml.h index 513cf0f03..38c86c3d6 100644 --- a/src/cfg_xml.h +++ b/src/cfg_xml.h @@ -21,11 +21,9 @@ enum xml_read_state { XML_READ_METRIC, XML_READ_WORKER, XML_READ_VARIABLE, - XML_READ_PIDFILE, - XML_READ_STATFILE_POOL, - XML_READ_FILTERS, XML_READ_LOGGING, XML_ERROR, + XML_READ_VALUE, XML_END }; @@ -40,6 +38,8 @@ struct rspamd_xml_userdata { /* Text is NULL terminated here */ typedef gboolean (*element_handler_func) (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); +/* Callbacks */ + /* Called for open tags <foo bar="baz"> */ void rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_name, @@ -92,4 +92,9 @@ gboolean handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); gboolean handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); gboolean handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); + + +/* Dumper functions */ +gboolean xml_dump_config (struct config_file *cfg, const char *filename); + #endif diff --git a/src/main.c b/src/main.c index fd250781d..350199632 100644 --- a/src/main.c +++ b/src/main.c @@ -638,6 +638,12 @@ main (int argc, char **argv, char **env) } fclose (f); + /* Dump it to xml */ + if (get_config_checksum (rspamd->cfg)) { + xml_dump_config (rspamd->cfg, "/tmp/rspamd.xml"); + } + /* Do post-load actions */ + post_load_config (rspamd->cfg); /* Init counters */ counters = rspamd_hash_new_shared (rspamd->server_pool, g_str_hash, g_str_equal, 64); |